vue3升级(持续优化⛽️)

367 阅读3分钟

1、新建一个vue3项目
新建项目指南

2、将项目的配置文件复制过来 image.png 其中eslint配置需要修改成vue3相匹配的规则推荐

// .eslintrc.js
module.exports = {
  // ESLint 一旦发现配置文件中有 "root": true,它就会停止在父级目录中寻找。
  root: true,
  // 指定脚本的运行环境。每种环境都有一组特定的预定义全局变量。
  env: {
    browser: true,
  },
  // 启用的规则
  extends: [
    'plugin:vue/vue3-recommended',
  ],
  parserOptions: {
    // js的版本
    ecmaVersion: 13,
    // 解析器
    parser: '@typescript-eslint/parser',
    // 模块化方案
    sourceType: 'module',
    // 支持jsx语法
    ecmaFeatures: {
      jsx: true
    }
  },
  // 引用的插件  下载的插件去掉eslint-plugin-前缀引入
  plugins: ['vue', '@typescript-eslint', 'import', 'node', 'promise'],
  // 自定义规则
  rules: {},
}

3、安装eslint中相关插件和模块

npm install typescript @typescript-eslint/parser eslint-plugin-@typescript-eslint
npm install eslint-plugin-import eslint-plugin-node eslint-plugin-promise

4、启动项目,解决报错

  • Cannot find module 'compression-webpack-plugin'
npm install compression-webpack-plugin@6.1.1
  • babel-polyfill in multi (webpack)-dev-server/client
npm install babel-polyfill
  • 解决 NPM 安装应用出现 ERESOLVE 错误 版本不匹配
npm install xxx --legacy-peer-deps

5、移入index.html
修改vue.config.js中vue的cdn地址

6、移入main.js、app.vue

// 修改前
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import http from '@/assets/js/http';
import common from '@/assets/js/common';
import { JsEnum } from '@/assets/js/JsEnum';
import loader from '@/components/SlotLoader';
import asyncLoader from '@/components/AsyncLoader';
import "@/assets/icon/iconfont.css";
import rulePolicy from '@/assets/js/directives/rule-policy.js';
import model from '@/assets/js/model.js';
import draggable from 'vuedraggable';

Vue.directive(rulePolicy.name, rulePolicy.rule(store, bus, http));
Vue.use(http);
Vue.prototype.common = common;
Vue.prototype.JsEnum = JsEnum;
Vue.prototype.model = model;
Vue.prototype.$moment = moment;
Vue.prototype.$momenttz = momenttz;
Vue.component('loader', loader);
Vue.component('async-loader', asyncLoader);
Vue.component('svg-icon', svgIcon);
Vue.component('draggable', draggable);

new Vue({
	el: '#app',
	router,
	store,
	components: { App },
	template: '<App/>'
});

// 修改后
import { createApp } from 'vue';
import App from './App.vue';
import http from '@/assets/js/http';
import common from '@/assets/js/common';
import { JsEnum } from '@/assets/js/JsEnum';
import bus from '@/assets/js/bus';
import loader from '@/components/SlotLoader';
import asyncLoader from '@/components/AsyncLoader';
import draggable from 'vuedraggable';
import rulePolicy from '@/assets/js/directives/rule-policy.js';
import model from '@/assets/js/model.js';
const app = createApp({
	components: { App },
	template: '<App/>'
})

app.directive(rulePolicy.name, rulePolicy.rule(store, bus));
app.use(store)
app.use(router)
app.use(http)
app.mount('#app');

app.component('Loader', loader);
app.component('AsyncLoader', asyncLoader);
app.component('Draggable', draggable);

app.config.globalProperties.common = common;
app.config.globalProperties.JsEnum = JsEnum;
app.config.globalProperties.model = model;

// 修改前
import Router from 'vue-router';
const router = new Router({
	mode: 'history',
	routes: routes,
	base: common.getTS(),
	fallback: false
});
// 修改后
import {createRouter} from 'vue-router';
const router = createRouter({
  history: createWebHistory(common.getTS()),
  routes: routes,
});
// 修改前
import Vuex from 'vuex';
const store = new Vuex.Store({
	state,
	getters,
	mutations,
	actions
});
// 修改后
import { createStore } from 'vuex';
const store = createStore({
	state,
	getters,
	mutations,
	actions
});
  • 安装包 image.png npm i svg-sprite-loader npm i -S vuedraggable@next
  • [@vue/compiler-sfc] the >>> and /deep/ combinators have been deprecated. Use :deep() instead. vscode使用正则替换
// 匹配字段
/deep/(.*) \{
// 替换字段
:deep($1) {
// 匹配前
/deep/ thead {
// 匹配后
:deep(thead) { 
// 修改前
import VueI18n from 'vue-i18n';
const i18n = new VueI18n({
    ...options
})
app.use(i18n)
// 修改后
import {createI18n} from 'vue-i18n';
const i18n = createI18n({
    ...options
})
app.use(i18n)

note!获取复杂数据类型需要更换api vue i18n v9的迁移后的$t()无法获取数组、对象

// 修改前
this.$t('navmenu');
// 修改后
this.$tm('navmenu');

slot attributes are deprecated

<!-- 修改前 -->
<a slot="other" href="javascript:;">{{$t('footer.department')}}</a>
<!-- 修改后 -->
<template #other>
  <a href="javascript:;">{{ $t('footer.department') }}</a>
</template>

正则匹配(仅适用部分情况,换行情况不知道要怎么匹配,菜菜子😣)
<div slot="content">(.*)</div>
<template #content><div>$1</div></template>

  • v-for的key值绑定

<template v-for> key should be placed on the <template> tag

<!-- 修改前 -->
<template v-for="(subItem, subIndex) in item.ChildrenNodes">
    <div :key="subIndex"></div>
</template>
<!-- 修改后 -->
<template v-for="(subItem, subIndex) in item.ChildrenNodes" :key="subIndex">
    <div></div>
</template>
  • .native被弃用

'.native' modifier on 'v-on' directive is deprecated

<!-- 修改前 -->
<div @click.native="handleClick"></div>
<!-- 修改后 -->
<div @click="handleClick"></div>
  • 改写axios全局挂载
// http.js
// 修改前
function install (app) {
    Object.defineProperties(Vue.prototype, {
        $http: {
            get () {
                if (!self) {
                    self = this;
                }
                return axios;
            }
        }
    });
}
// 修改后
function install (app) {
  app.config.globalProperties.$http = axios
}
  • this.set修改[vue2升级vue3正则处理this.set修改 [vue2升级vue3正则处理this.set](juejin.cn/post/706494…)

匹配字段

this\.\$set\((.*),\s?['|"](.*)['|"],\s?(.*)\)
this\.\$set\((.*),\s?['|"](.*)['|"],\s?(.*)\);

替换字段

$1.$2 = $3

  • render方法改造
// 修改前
render(h){
    return h()
}
// 修改后
import { h } from 'vue'
render(){
    return h()
}
  • 遇到一个很奇怪的问题;导入部分组件后没有更改文件webpack也会自动重新编译 调试发现是组件名称不规范导致的
// 修改前
export default {
    name: "Achievement.PC.Setting",
};
// 修改后
export default {
    name: "AchievementPCSetting",
};
  • this._l替换

这是vue原型上渲染列表的方法,在vue3中可以直接从vue中导出renderList方法进行使用

// 修改前
const tabs = this._l(panes, (pane, index) => {
    ......
}
// 修改后
import { renderList } from 'vue'
const tabs = renderList(panes, (pane, index) => {
    ......
}
  • 获取slots不兼容处理
// 修改前
this.$slots.default.filter(v => {
    ......
})
// 修改后
const slots = this.$slots.default && this.$slots.default()
slots.filter(v => {
    ......
})
  • ts声明全局变量

新建global.d.ts文件

interface Window {
  lang: string;
}

🌰:定义以下数据结构可以动态声明索引类型

"Common": {
    "dev": {
        "a": "xxx",
        "b": "xxx",
        ...
    },
    "prod": {
        "a": "xxx",
        "b": "xxx",
        ...
    },
    "yun": {
        "a": "xxx",
        "b": "xxx",
        ...
    },
    "API": {
        "logOut": {
            "Method": "POST",
            "URL": "/api/Logout"
        },
    }
},
interface IApi {
  [key: string]: {
    Method: 'post' | 'POST' | 'get' | 'GET';
    URL: string;
  };
}

interface IUrl {
  [key: string]: string;
}

interface ICommonItem {
  [key: string]: IUrl | IApi;
  API: IApi;
}