Vue2 升级 Vue3 注意点
挂载全局对象和方法
Vue3
已经不支持直接 Vue.prototype.$xxx = xxx
这种方式来挂载全局对象,这是由于 globalVue
不再是构造函数,因此不再支持该构造函数。
可以通过 config.globalProperties
进行全局挂载。
js
import { createApp } from "vue";
import App from "./App.vue";
const app = createApp(App);
// Vue3全局挂载名称
app.config.globalProperties.$vueName = "Vue3全局挂载名称";
app.mount("#app");
js
import { defineComponent, getCurrentInstance } from "vue";
export default defineComponent({
setup() {
// 获取全局挂载的实例
const { proxy } = getCurrentInstance();
console.log(proxy.$vueName);
return {};
},
});
事件总线问题
Vue3
中不可以使用 new Vue()
的方式来使用事件总线。
主要原因是:
方案 1: 使用第三方事件总线。
如 vue3-eventbus
, mitt
。
方案 2: 自己实现一个简单的事件总线。
js
export default class EventBus {
constructor() {
this.events = {};
}
emit(eventName, data) {
if (this.events[eventName]) {
this.events[eventName].forEach(function (fn) {
fn(data);
});
}
}
on(eventName, fn) {
this.events[eventName] = this.events[eventName] || [];
this.events[eventName].push(fn);
}
off(eventName, fn) {
if (this.events[eventName]) {
for (var i = 0; i < this.events[eventName].length; i++) {
if (this.events[eventName][i] === fn) {
this.events[eventName].splice(i, 1);
break;
}
}
}
}
}
装饰器替代方案
使用 https://facing-dev.github.io/vue-facing-decorator/#/zh-cn/readme
js
import { Component, Vue } from "vue-facing-decorator";
@Component
export default class MyComponent extends Vue {
// 这是一个vue响应式属性
text = "Example code";
// 这是一个vue组件方法
method() {
console.log(this.text);
}
// 这是一个vue生命周期钩子
mounted() {
this.method();
}
}
vuex-class
目前业界没有代替方案,手动改成原始写法,或者自己实现装饰器。
一个思路:
vuex-class
使用了 vue-class-component
的自定义装饰器实现,具体可查看源码:
https://github.com/ktsn/vuex-class/blob/master/src/bindings.ts
js
import { createDecorator } from "vue-class-component";
其实 vue-facing-decorator
也提供了自定义装饰器,但只在 vue-facing-decorator 2.x
文档中看到 3-beta
中消失了。
https://facing-dev.github.io/vue-facing-decorator/#/en/custom/custom
ts
import { createDecorator, Component, Vue } from "vue-facing-decorator";
function Log(prefix: string) {
return createDecorator(function (options, key) {
const old = options.methods?.[key];
if (!old) {
throw "not found";
}
options.methods[key] = function (...args: any[]) {
old.apply(this, args);
};
});
}
@Component
export default class Comp extends Vue {
@Log("prefix")
method() {}
}
props 不规范用法导致的报错
在升级项目的时候,发现项目中有对 props 中的内容做修改的代码,如:
js
this.xxx = xx; // xxx 是个 prop
这种方式在 Vue2
中不会引发 crash
,但在 Vue3
中会。
解决方案:移除不规范的用法。
路由 params 传递对象的不规范用法导致报错
旧版的路由可以将一个 Object
作为 params
传递,新版路由将无法使用这种方式,必须是基础类型。
解决方案:移除不规范的用法。
i18n 问题
项目中有一些老旧的写法,最多的问题是:
js
$t("xxx", { 0: "x", 1: "xx" }); // 这种写法在新的 i18n 中报错
需要改成:
js
$t("xxx", ["x", "xx"]);
TIP
如果不想一个个改,可以使用全局 t
函数替换法。
echarts 等类库异常
本身 echarts
部分应该是和 Vue
无关的,但是我们发现 Vue3
的 proxy
包装会影响 echarts
实例的部分功能。
这部分问题应该是 Vue3
的响应式机制引起的,解决方式是 echarts
实例不要使用响应式对象。
element 样式问题
这个是我们在项目中花最多时间去处理的问题,因为我们项目对 element-ui
进行了比较高度的定制化,升级到 element-plus
之后,由于 class
的结构发生了变化,很多页面发生了样式错乱。
解决方案:暂无自动化方案,需要人工介入。
element 类型问题
针对 TypeScript
的项目,element-ui
中有个 types
目录可以提供类型,但升级 element-plus
之后,这个目录没有了。
解决方案:直接从 element-plus
引入,然后通过 TypeScript
的工具类型转换成需要的类型。
ts
import { ElSelect } from "element-plus";
type ElSelectInstanceType = InstanceType<typeof ElSelect>;
element 时间选择器问题
- 选择器的默认时间需要从
string
类型改为Date
类型 - 选择器的
option
需要使用新的书写方式,具体看官方文档。
element popover 手动触发问题
项目中好多 popover
使用了手动触发模式,这个模式在 plus
中需要加 trigger
去掉。然后将 v-model
修改为 visible
。
element 图标库的不兼容
plus
中使用了 svg
作为图标,和之前 font
方式区别较大,如果为了兼容,可以引入之前的 font-face
。