前言
Vue3 发布作为默认版本将近一年了,手里的 Vue2 项目,希望最低成本的能使用 Vue3 的新特性:Composition Api、组合式 API、v-bind() in CSS、template 中的可选链等。正好年初事情较少,因此决定升级至 Vue2.7,该版本支持 Vue3 中一些最重要的功能,让 Vue2 的用户也能从中受益,并为可能迁移到 Vue3 做好更好的准备。
2022 年 7 月 1 号,Vue2.7 正式发布,Vue2.7 是 Vue2.X 的最终次要版本,在这个版本之后,Vue2 将进入 LTS(长期支持),即从发布开始持续 18 个月,Vue2 将不再接收新功能。
本文记录升级过程并总结一些经验,欢迎感兴趣的小伙伴阅读。
项目版本:vue@2.6.14 vue-cli@4.4.0
Vue2.7 新特性介绍及官方指南:blog.vuejs.org/posts/vue-2…
具体实践:
1.vue、@vue/cli-xxx 更新
-
v4 版本的@vue/cli-xxx,升级到~4.5.18
-
v5 版本的@vue/cli-xxx,升级到~5.0.6
// package.json
{
"dependencies": {
// "vue": "2.6.14",
"vue": "2.7.0"
}
"devDependencies": {
// "@vue/cli-plugin-babel": "~4.4.0",
// "@vue/cli-plugin-eslint": "~4.4.0",
// "@vue/cli-plugin-router": "^4.4.0",
// "@vue/cli-plugin-vuex": "^4.4.0",
// "@vue/cli-service": "~4.4.0",
"@vue/cli-plugin-babel": "~4.5.18",
"@vue/cli-plugin-eslint": "~4.5.18",
"@vue/cli-plugin-router": "~4.5.18",
"@vue/cli-plugin-vuex": "~4.5.18",
"@vue/cli-service": "~4.5.18",
// 在2.7版本中不再需要`vue-template-compiler`,可移除
// 注意:如果项目中引入了`@vue/test-utils`,则需要保留`vue-template-compiler`
// "vue-template-compiler": "2.6.14",
}
}
2.删除 node_modules 和 package-lock.json
为防止某些未列出的依赖项(如下)不满足版本要求,建议删除node_modules和package-lock.json,并重新 install,以确保升级到最新版本。
- `vue-loader`: `^15.10.0`
- `vue-demi`: `^0.13.1`
3.@vue/composition-api
项目中已经使用了@vue/composition-api,则移除 main.js 的注册代码,并将相应 import 导入更新为vue。
注:2.7 版本未移植的一些 API(例如createApp)仍然需要使用@vue/composition-api
// main.js
// import VueCompositionAPI from '@vue/composition-api'
// Vue.use(VueCompositionAPI)
// 引入的地方
// import { ref, reactive } from '@vue/composition-api'
import { ref, reactive } from 'vue'
4.eslint-plugin-vue 升级 v9+
如果使用<script setup>有未使用的变量 lint 错误提示,需要升级eslint-plugin-vue至 9+版本。
升级后项目启动报错,原因:配置了多余参数:
官网(eslint.vuejs.org/rules/max-a… )查了下,没有了 allowFirstLine 的配置,删除后正常运行。
5.深度选择器改写::v-deep、/deep/为:deep()
更新后,如果有::v-deep、/deep/相关的报错或者警告,需要改用:deep()
<style scoped>
.a :deep(.b) { /* ... */ }
</style>
6.vue2.7 与@vue/composition-api 的 setup 参数差异
之前使用@vue/composition-ap的时候有用到 root 调用全局定义的方法:
setup(props,{ root }){
// 调用全局定义的方法
root.xxxx
}
在升级后发现 setup 第二个参数将 root 等属性移除了, 原先 setup 第二个参数包含
setup(props, { slots, emit, attrs, root, parent, refs, listeners, isServer, ssrContext })
从截图的createSetupContext方法中可以看到 vue2.7 只包含了attrs, listeners, slots, emit, expose;在 vue3 中 listeners也被移除。
解决方案:使用了getCurrentInstance方法替代(后面会对该方法介绍)。
import { getCurrentInstance } from 'vue'
...
setup(){
const root = getCurrentInstance().proxy
}
7.setup 中使用 vuex、vue-router
由于项目版本 vuex、vue-router 均为 v3,组合式 API 中,我们需要使用一些新的函数来代替访问 this等方法,如:this.$store、this.$router、this.$route。
解决方案:也用到了 getCurrentInstance,通过它封装一些方法使用。
import { getCurrentInstance } from 'vue'
export function useStore() {
const { proxy } = getCurrentInstance()
const store = proxy.$store
return store
}
export function useRoute() {
const { proxy } = getCurrentInstance()
const route = proxy.$route
return route
}
export function useRouter() {
const { proxy } = getCurrentInstance()
const router = proxy.$router
return router
}
还有一些其他写法可以参考此 issue:github.com/vuejs/vue-r…
然而组合式 API 下 vuex 的mapState, mapGetters, mapActions 和 mapMutations 辅助函数依然是无法使用的。可以尝试vuex-composition-helpers这个库,帮助轻松使用 Vuex 和 Composition API。
补充:关于 getCurrentInstance
注意:getCurrentInstance 作为访问内部组件实例的方法,官方是不鼓励在应用程序代码中使用的,下面贴上官方原文及例子:
import { getCurrentInstance } from 'vue'
const MyComponent = {
setup() {
const internalInstance = getCurrentInstance()
internalInstance.appContext.config.globalProperties // access to globalProperties
}
}
并且 getCurrentInstance 只在 setup 或生命周期钩子中工作:
const MyComponent = {
setup() {
const internalInstance = getCurrentInstance() // works
const id = useComponentId() // works
const handleClick = () => {
getCurrentInstance() // doesn't work
useComponentId() // doesn't work
internalInstance // works
}
onMounted(() => {
getCurrentInstance() // works
})
return () =>
h(
'button',
{
onClick: handleClick
},
`uid: ${id}`
)
}
}
// also works if called on a composable
function useComponentId() {
return getCurrentInstance().uid
}
总结
Vue2.7 版本的升级过程总的来说,还算顺利。感谢大家阅读,如有补充或者文中有描述不正确的地方,欢迎留言交流。