一、代码移植原则
前置说明:根据项目开发的实际情况,本次升级不采用Typescript。
升级的原则是开始尽量的简单配置,将代码分阶段逐步移植到新版本框架上,遇到问题逐一排查解决。
大致阶段,可以分为:
第一阶段:项目运行依赖的基本代码移植,主要涉及:Nuxt配置,UI框架(Element-UI),store(由Vuex改为pinia), 插件,中间件,http请求,工具函数及其它全局对象相关的代码
第二阶段:移植layouts布局文件及pages页面代码,将Vue2代码语法改为Vue3代码语法
第三阶段:解决前面两个阶段在代码移植过程中遗漏或者暂时不予解决的问题(但又不影响主要代码的移植和运行,比如一些第三方组件或者插件的使用在移植过程中遇到问题)
二、nuxt配置
首先从nuxt.config.js的配置文件开始:
先看一下原有Nuxt2的配置,如下
通过分析代码,可以先迁移css
、plugins
及modules
的部分比较主要的配置:
如上所示,下一步需要迁移的相关配置,涉及:
①Element-Plus框架的引入(Element-UI需要替换为Element-Plus)
②项目Css样式文件
③http请求的封装(Nuxt3不再建议使用Axios)
④Vue相关扩展、全局组件及过滤器的替换(Vue3已经移除了Filter)
⑤Vuex的迁移(改为Pinia)
详细的迁移如下:
1.Element-Plus引入
(1)先安装Element Plus:
pnpm install element-plus
(2)安装Nuxt官方专门针对引入Element Plus 开发的模块:
pnpm i @element-plus/nuxt -D
(3)在nuxt.config.ts中配置modules参数:
export default defineNuxtConfig({modules: ['@element-plus/nuxt'],elementPlus: { /** Options */ }
})
2.项目css样式
export default defineNuxtConfig({modules: [ '@element-plus/nuxt'],css: ['~/assets/style.css']
})
3.http请求的封装
由于项目中大量使用到$http
对象,这个对象其实是对axios的封装,主要有两种使用方式:
①在asyncData函数中使用ctx.app.$http
②在Vue实例对象上使用this.$http
这两种方式分别对应的绑定代码:
① app.$http:
// 这里是 为了在 asyncData 方法中使用
export default ({ app }, inject) => {// Set the function directly on the context.app objectapp.$http = http
}
②Vue.prototype.$http:
Vue.prototype.$http = http
以上代码都是在plugins/main.js
中实现(接下来,也需要迁移这个文件代码),我们先实现对http的封装:
在utils目录下新建http.js文件,文件内容如下:
/**
* nuxt项目目录/utils/http.js
* 基于useFetch()的网络请求封装
*/
import md5 from 'md5'
import qs from 'qs'//全局基础URL
const BASEURL = "https://xxxx"; //全局后台服务器请求地址
const COMMON_HEADERS = {'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8','Accept': 'application/json'
}/*** 网络请求方法* @param obj 请求参数* @returns 响应结果*/
const request = (obj) => {const sault = obj.url.split('/')[2]const userIp = useCookie('x-user-ip')const nuxtApp = useNuxtApp()let baseData = {...signStamp(sault),guard: userIpMd(userIp.value || '-')}let queryData = nulllet bodyData = nullif(obj.method == 'get') {queryData = Object.assign({}, obj?.params || {}, baseData)} else if(obj.method == 'post') {bodyData = qs.stringify(Object.assign({}, obj?.data || {}, baseData), { indices: false })}return new Promise(async (resolve, reject) => {const options = {baseURL: BASEURL,key: md5(obj.url + (queryData || bodyData)??(JSON.stringify(queryData || bodyData))),method: obj.method,query: queryData,body: bodyData,timeout: 20000,onRequest({ request, options }) {// 设置请求报头options.headers = Object.assign(COMMON_HEADERS, options.headers || {})/**如果接口需求携带token请求,则可先自行使用官方的useCookie()方法设置Cookie存储后,再使用useCookie()方法,取出token使用。如下例子:*///const token = useCookie('token')//options.headers.Authorization = token.value||null},onRequestError({ request, options, error }) {// 处理请求错误console.log("服务器链接失败!")reject(error)},onResponse({ request, response, options }) {},onResponseError({ request, response, options }) {// 处理响应错误return response}}if(process.client && !nuxtApp.isHydrating) {const res = await $fetch(obj.url, options)resolve(res)} else {const { data } = await useFetch(obj.url, options)resolve(data.value)}})
}export const httpGet = (url, payload = undefined,headers = undefined, cache = false) => {return request({method: 'get',url: url,params: payload,headers: headers}).then(rsp => {return rsp})
}export const httpPost = (url, payload = undefined,headers = undefined, cache = false) =>{return request({method: 'post',url: url,data: payload,headers: headers}).then(rsp => {return rsp})
}export const $http = {get: httpGet,post: httpPost
}
以上代码比较粗略,仅供参考(其中使用的第三方依赖需要前置安装,部分函数不给出实现,按需要删减代码)
4.Vue相关扩展、全局组件及过滤器的替换
这部分也是在plugins/main.js
中定义,所以接下来迁移plugins/main.js
中的代码:
①Vue相关原型扩展:
原代码:
迁移后:
在utils目录中新建extend.js:
②全局组件:
迁移到components目录,如遇到报错先暂时修复
③过滤器
原代码:
直接废除过滤器的写法,改到utils的extend.js中:
至此plugins/main.js中的代码已经都迁移完成,文件已经没有什么作用,也就不需要这个文件了。
5.Vuex的迁移
Vue3我们搭配改用Pinia:
①安装pinia:
pnpm install pinia @pinia/nuxt
②nuxt.config.js中配置pinia:
export default defineNuxtConfig({// ... 其他配置modules: [// ...'@pinia/nuxt',],
})
③在store目录创建index.js文件:
import { defineStore } from 'pinia'export const useMainStore = defineStore('main', {state: () => ({token:"",...}),actions: {settoken(token){this.token=token},...}
})
④pinia封装插件:
在plugins目录新建pinia.js:
import { useMainStore } from '~/store'export default defineNuxtPlugin(({ $pinia }) => {return {provide: {store: useMainStore($pinia)}}
})
这样代码中就可以使用以下方式进行调用:
const { $store } = useNuxtApp()$store.xxx // 属性或者actions
⑤修改现有代码中使用到store的代码:
注意Vuex和Pinia在语法上的差别,进行等效替代,比如在actions上的调用方式,两者就有区别。
最后一起看一下,迁移后的Nuxt.config.js如下:
export default defineNuxtConfig({devtools: { enabled: true },modules: ['@pinia/nuxt', '@element-plus/nuxt'],plugins: [],css: ['~/assets/style.css']
})