5

最近从零到一开发了一个门户网站,因对seo有要求,所以选择nuxt.js搭配typescript,期间遇到不少问题,最终都一一解决了,留下一个demo供参考,如果能帮到大家,帮忙给个star,感谢!demo地址

以下是我的部分总结(后续抽空会再补充):

一、axios

建议直接使用nuxtjsaxios模块。

1.安装并引入@nuxtjs/axios

需要代理请一并安装引入@nuxtjs/proxy

nuxt.config.js中:

export default {
    modules:[
        '@nuxtjs/axios',
        '@nuxtjs/proxy'
    ],
    axios: {
        proxy: true,
        baseURL: '',
        prefix: '/api-prefix',
        credential: true
    },
    proxy: {
        '/api-prefix': {
            target: 'http://...',
            changeOrigin: true,
            pathRewrite: {
                '^/api-prefix': '',
                changeOrigin: true
            }
        }
    },
    ...
}

2.axios拦截

plugins目录下,新增axios-accessor.ts文件:

plugins/axios-accessor.ts中:

import { Plugin } from '@nuxt/types'
import { AxiosResponse, AxiosRequestConfig, AxiosError } from 'axios'

const accessor: Plugin = ({ error }) => {

  $axios.onRequest((config: AxiosRequestConfig) => {
    // ...
    return config
  })
  
  $axios.onError((e: AxiosError<any>) => {
    // ...
  })
  
  // response拦截器,数据返回后,你可以先在这里进行一个简单的判断
  $axios.interceptors.response.use((response: AxiosResponse<any>) => {
    const res = response
    if (res.status === 200) {
      return Promise.resolve(res)
    } else {
      return Promise.reject(res)
    }
  },
  (e: any) => {
    const { status, data } = e.response
    error({ statusCode: status, message: data })
    return Promise.reject(e)
  })
}

export default accessor

然后应用新增的plugin/axios-accessor.ts

nuxt.config.js中新增如下配置:

export default {
    ...
    plugins: [
        '@/plugins/axios-accessor'
    ]
}

3.非vue文件中使用$axios对象

nuxtjs中的axios模块会在vue实例上挂载一个$axios对象供使用,实际开发过程中,我们往往习惯将项目中api方法放在单独的模块供全局使用,如何在非vue文件中使用$axios对象呢?

nuxtjs官网提供的typescript文档中,在vuex的store初始化示例中,有一并讲到,传送门:https://typescript.nuxtjs.org...

utils/api.ts中:

import { NuxtAxiosInstance } from '@nuxtjs/axios'

let $axios: NuxtAxiosInstance

export function initializeAxios (axiosInstance: NuxtAxiosInstance) {
  $axios = axiosInstance
}

export { $axios }
plugin/axios-accessor.ts中:

import { Plugin } from '@nuxt/types'
import { AxiosResponse, AxiosRequestConfig, AxiosError } from 'axios'
// 新增引入
import { initializeAxios } from '~/utils/api'

const accessor: Plugin = ({ error, app: { $axios } }) => {
  // 此处调用
  initializeAxios($axios)
  
  $axios.onRequest((config: AxiosRequestConfig) => {
    // ...
    return config
  })
  
  $axios.onError((e: AxiosError<any>) => {
    // ...
  })
  
  // response拦截器,数据返回后,你可以先在这里进行一个简单的判断
  $axios.interceptors.response.use((response: AxiosResponse<any>) => {
    const res = response
    if (res.status === 200) {
      return Promise.resolve(res)
    } else {
      return Promise.reject(res)
    }
  },
  (e: any) => {
    const { status, data } = e.response
    error({ statusCode: status, message: data })
    return Promise.reject(e)
  })
}

大功告成,后续在其他文件中,只需:
import { $axios } from '@/utils/api'
就可以直接使用啦!

二、store

nuxtjs官方文档所说,Nuxt.js 支持两种使用 store 的方式,你可以择一使用:

  • 模块方式: store 目录下的每个 .js 文件会被转换成为状态树指定命名的子模块 (当然,index 是根模块)
  • Classic(不建议使用): store/index.js返回创建Vuex.Store实例的方法。

结合ts当然是使用 vuex-module-decorators来创建modules。

store/myModule.ts中:

import { Module, VuexModule, Mutation } from 'vuex-module-decorators'

@Module({
  name: 'myModule',
  stateFactory: true,
  namespaced: true,
})
export default class MyModule extends VuexModule {
  wheels = 2

  @Mutation
  incrWheels(extra) {
    this.wheels += extra
  }

  get axles() {
    return this.wheels / 2
  }
}
utils/store-accessor.ts中:

import { Store } from 'vuex'
import { getModule } from 'vuex-module-decorators'
import MyModule from '~/store/myModule'

let myModule: MyModule

function initialiseStores(store: Store<any>): void {
  myModule = getModule(MyModule, store)
}

export { initialiseStores, myModule }
store/index.ts中:

import { Store } from 'vuex'
import { initialiseStores } from '~/utils/store-accessor'

const initializer = (store: Store<any>) => initialiseStores(store)

export const plugins = [initializer]
export * from '~/utils/store-accessor'

然后就可以愉快的使用啦!

三、cookie

关于cookie这一块,以前一直用的是js-cookie这个库,这次的nuxtjs项目中,mode: 'universal'模式下,服务端渲染时没办法获取到客户端缓存的cookie,导致页面刷新后无法立即通过cookie拿到用户缓存的登录状态,因此后来改用cookie-universal-nuxt这个库,api与js-cookie基本一致,可在服务端使用,引入后,会在vue实例上新增一个 $cookie对象,为方便全局使用,可仿照$axios的accessor逻辑,如下example:

1.首先安装并引入

npm install cookie-universal-nuxt --save
nuxt.config.js中:

export default {
    module: [
        '@nuxtjs/axios',
        '@nuxtjs/proxy',
        'cookie-universal-nuxt'
    ],
    ...
}

2.cookie的accossor

utils/api.ts中:

import { NuxtAxiosInstance } from '@nuxtjs/axios'
import { NuxtCookies } from 'cookie-universal-nuxt'

let $axios: NuxtAxiosInstance

export function initializeAxios (axiosInstance: NuxtAxiosInstance) {
  $axios = axiosInstance
}

let $cookies: NuxtCookies

export function initializeCookies (cookiesInstance: NuxtCookies) {
  $cookies = cookiesInstance
}

export { $axios, $cookies }
plugin/axios-accessor.ts中:

import { Plugin } from '@nuxt/types'
import { AxiosResponse, AxiosRequestConfig, AxiosError } from 'axios'
// 新增引入
import { initializeAxios, initializeCookies } from '~/utils/api'

const accessor: Plugin = ({ error, app: { $axios, $cookies } }) => {
  // 此处调用
  initializeAxios($axios)
  initializeCookies($cookies)
  
  $axios.onRequest((config: AxiosRequestConfig) => {
    // ...
    return config
  })
  
  $axios.onError((e: AxiosError<any>) => {
    // ...
  })
  
  // response拦截器,数据返回后,你可以先在这里进行一个简单的判断
  $axios.interceptors.response.use((response: AxiosResponse<any>) => {
    const res = response
    if (res.status === 200) {
      return Promise.resolve(res)
    } else {
      return Promise.reject(res)
    }
  },
  (e: any) => {
    const { status, data } = e.response
    error({ statusCode: status, message: data })
    return Promise.reject(e)
  })
}

在其他文件中,只需:
import { $cookies } from '@/utils/api'
就可以直接使用啦!

OK,先写这么多,有问题欢迎指出交流。再次附上demo地址


elvira0702
14 声望3 粉丝