Vue2升级Vue3中容易遇到的问题

最近在将一个运行了3年的Vue2项目升级到Vue3,过程中踩了不少坑,在此记录一下。

一、生命周期钩子

1. 被移除的钩子

  • beforeDestroy → 改用 beforeUnmount
  • destroyed → 改用 unmounted

2. 组合式API中的异步陷阱

// 错误示例:在setup中直接调用异步钩子  
setup() {  
  onMounted(async () => {  
    await fetchData(); // 可能导致内存泄漏  
  });  
}  

// 正确方案:分离异步逻辑  
setup() {  
  const loadData = async () => { /* ... */ };  

  onMounted(() => {  
    loadData();  
  });  
}  

二、模板语法

1. v-model的破坏性变更

<!-- Vue 2:value + @input -->  
<Child v-model="pageTitle" />  

<!-- Vue 3:modelValue + update:modelValue -->  
<Child v-model:title="pageTitle" />  

<!-- 多v-model支持 -->  
<Form v-model:name="name" v-model:age="age" />  

2. 事件监听符的变更

<!-- Vue 2监听原生事件 -->  
<comp @click.native="handleClick" />  

<!-- Vue 3移除.native -->  
<comp @click="handleClick" />  

<!-- 需要传递原生事件时 -->  
<comp v-on="listeners" />  

三、全局API

1. Vue.prototype的替代方案

// Vue 2全局挂载  
Vue.prototype.$http = axios;  

// Vue 3使用provide/inject  
// main.js  
app.provide('http', axios);  

// 组件中获取  
const http = inject('http');  

2. 过滤器(Filter)的废弃处理

// 旧版过滤器  
{{ price | currency }}  

// 替代方案:全局方法/计算属性  
// 注册全局方法  
app.config.globalProperties.$currency = (val) => `¥${val}`;  

// 模板中使用  
{{ $currency(price) }}  

四、第三方库的兼容性问题

1. elementUI的版本适配

# Element UI → Element Plus  
npm uninstall element-ui  
npm install element-plus @element-plus/icons-vue  

# 按需引入配置变更  
// vite.config.js  
import AutoImport from 'unplugin-auto-import/vite';  
import Components from 'unplugin-vue-components/vite';  
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';  

plugins: [  
  AutoImport({ resolvers: [ElementPlusResolver()] }),  
  Components({ resolvers: [ElementPlusResolver()] })  
]  

2. Vuex到Pinia的迁移

// Vuex模块化  
const moduleA = {  
  state: () => ({ count: 0 }),  
  mutations: { increment(state) { state.count++ } }  
}  

// Pinia等效实现  
export const useStore = defineStore('moduleA', {  
  state: () => ({ count: 0 }),  
  actions: {  
    increment() { this.count++ }  
  }  
});  

五、项目配置

1. Vue CLI到Vite的迁移

// 旧版vue.config.js → vite.config.ts  
// 路径别名配置变更  
resolve: {  
  alias: {  
    '@': path.resolve(__dirname, './src')  
  }  
}  

// 环境变量前缀变更  
// 原process.env → import.meta.env  
VITE_API_URL=xxx # .env文件需以VITE_开头  

2. IE11兼容性处理

# 安装polyfill  
npm install @vitejs/plugin-legacy --save-dev  

# vite.config.js  
import legacy from '@vitejs/plugin-legacy';  

plugins: [  
  legacy({  
    targets: ['defaults', 'not IE 11'] // 明确放弃IE11  
  })  
]