Vue2 迁移到 Vue3

30 篇文章 0 订阅
12 篇文章 0 订阅

一.《Vue 3 迁移指南》参考文档:https://v3-migration.vuejs.org/zh/

二.Vue 3 中需要关注的一些新特性。
1. 组合式 API*;
2. 单文件组件中的组合式 API 语法糖 (<script setup>)*;
3. Teleport 组件;
4. Fragments 片段;
5. Emits 组件选项**;
6. 来自 @vue/runtime-core 的 createRenderer API 用来创建自定义渲染函数;
7. 单文件组件中的状态驱动的 CSS 变量 (<style> 中的 v-bind)*;
8. SFC <style scoped> 新增全局规则和针对插槽内容的规则;
9. Suspense 实验性。

* 现在也支持在 Vue 2.7 中使用,
** Vue 2.7 中支持,但仅用于类型推断。

三.新的框架级别推荐。
Vue 3 的支持库进行了重大更新。以下是新的默认建议的摘要:
1. 新版本的 Router, Devtools & test utils 来支持 Vue 3;
2. 构建工具链: Vue CLI -> Vite【https://cn.vitejs.dev/】
3. 状态管理: Vuex -> Pinia【https://pinia.vuejs.org/zh/index.html】
4. IDE 支持: Vetur -> Volar【https://marketplace.visualstudio.com/items?itemName=vue.volar】
5. 新的 TypeScript 命令行工具: vue-tsc【https://github.com/vuejs/language-tools/tree/master/vue-language-tools/vue-tsc】
6. 静态网站生成: VuePress -> VitePress【https://vitepress.dev/】
7. JSX: @vue/babel-preset-jsx -> @vue/babel-plugin-jsx【https://github.com/vuejs/babel-plugin-jsx】


四.用于迁移的构建版本。
@vue/compat (即“迁移构建版本”) 是一个 Vue 3 的构建版本,提供了可配置的兼容 Vue 2 的行为。

该构建版本默认运行在 Vue 2 的模式下——大部分公有 API 的行为和 Vue 2 一致,仅有一小部分例外。使用在 Vue 3 中发生改变或被废弃的特性时会抛出运行时警告。一个特性的兼容性也可以基于单个组件进行开启或禁用。

预期用例:
1. 将一个 Vue 2 应用升级为 Vue 3 (存在限制)。
2. 迁移一个库以支持 Vue 3。
3. 对于尚未尝试 Vue 3 的资深 Vue 2 开发者来说,迁移构建版本可以用来代替 Vue 3 以更好地学习版本之间的差异。

五.非兼容性改变。
参考文档:https://v3-migration.vuejs.org/zh/breaking-changes/

1. 全局API。
(1). 全局 Vue API 更改为使用应用程序实例。
Vue 2.x 有许多全局 API 和配置,它们可以全局改变 Vue 的行为。例如,要注册全局组件,可以使用 Vue.component API,虽然这种声明方式很方便,但它也会导致一些问题。从技术上讲,Vue 2 没有“app”的概念,Vue 2定义的应用只是通过 new Vue() 创建的根 Vue 实例。从同一个 Vue 构造函数创建的每个根实例共享相同的全局配置。

createApp是 Vue 3 中的 一个 新概念,调用 createApp 返回一个应用实例。
    import { createApp } from 'vue'
    const app = createApp({})

如果使用的是 Vue3 的 CDN 构建版本,那么 createApp 将通过全局的 Vue 对象暴露。
    const { createApp } = Vue
    const app = createApp({})

(2). 全局和内部 API 都经过了重构,现已支持 TreeShaking (摇树优化)。
由于之前的 Vue2 版本中的代码编写方式,如 Vue.nextTick() 这样的全局 API 是不支持 tree-shake 的,不管它们实际上是否被使用了,都会被包含在最终的打包产物中。

在 Vue 3 中,全局和内部 API 都经过了重构,并考虑到了 tree-shaking 的支持。因此,对于 ES 模块构建版本来说,全局 API 现在通过具名导出进行访问。例如:
    import { nextTick } from 'vue'
    nextTick(() => {
        // 一些和 DOM 有关的东西
    })

2. 模板指令。
(1). v-model 指令在组件上的使用已经被重新设计,替换掉了 v-bind.sync。

用于自定义组件时,v-model prop 和事件默认名称已更改:
prop:value -> modelValue;
事件:input -> update:modelValue;

v-bind 的 .sync 修饰符和组件的 model 选项已移除,可在 v-model 上加一个参数.lazy代替。

现在可以在同一个组件上使用多个 v-model 绑定,还可以自定义 v-model 修饰符。

(2). 在<template v-for> 和没有 v-for 的节点身上使用 key 发生了变化。

对于 v-if/v-else/v-else-if 的各分支项 key 将不再是必须的,因为现在 Vue 会自动生成唯一的 key。

如果你手动提供 key,那么每个分支必须使用唯一的 key。你将不再能通过故意使用相同的 key 来强制重用分支。

<template v-for> 的 key 应该设置在 <template> 标签上 (而不是设置在它的子节点上)。

(3). v-if 和 v-for 在同一个元素身上使用时的优先级发生了变化。

Vue2.x 版本中,在一个元素上同时使用 v-if 和 v-for 时,v-for 会优先作用。

Vue3.x 版本中 v-if 总是优先于 v-for 生效。

(4). v-bind="object" 现在是顺序敏感的。
在 Vue2.x 中,如果一个元素同时定义了 v-bind="object" 和一个相同的独立 attribute,那么这个独立 attribute 总是会覆盖 object 中的绑定。
示例:
    <!-- 模板 -->
    <div id="red" v-bind="{ id: 'blue' }"></div>
    <!-- 结果 -->
    <div id="red"></div>

在 Vue3.x 中,如果一个元素同时定义了 v-bind="object" 和一个相同的独立 attribute,那么绑定的声明顺序将决定它们如何被合并【后面覆盖前面】。

(5). v-on:event.native 事件修饰符已经被移除。

Vue3中 新增的 emits 选项允许子组件定义真正会被触发的事件。


3. 组件。
(1). 函数式组件只能通过纯函数进行创建。

Vue2.x 中函数式组件带来的性能提升在 Vue3.x中已经可以忽略不计,因此建议只使用有状态的组件。

Vue3.x中函数式组件只能由接收 props 和 context (即:slots、attrs、emit) 的普通函数创建。
 
(2). 单文件组件 (SFC) <template> 标签的 functional attribute 和函数式组件的 functional 选项已被移除。

(3). 异步组件现在需要通过 defineAsyncComponent 方法进行创建。

新的 defineAsyncComponent 助手方法,用于显式地定义异步组件。

component 选项被重命名为 loader。

Loader 函数本身不再接收 resolve 和 reject 参数,且必须返回一个 Promise。

Vue2异步组件是通过将组件定义为返回 Promise 的函数来创建的,例如:
    const asyncModal = () => import('./Modal.vue')

在 Vue 3 中,由于函数式组件被定义为纯函数,因此异步组件需要通过将其包裹在新的 defineAsyncComponent 助手方法中来显式地定义。
示例:
    import { defineAsyncComponent } from 'vue'
    import ErrorComponent from './components/ErrorComponent.vue'
    import LoadingComponent from './components/LoadingComponent.vue'

    // 不带选项的异步组件
    const asyncModal = defineAsyncComponent(() => import('./Modal.vue'))

    // 带选项的异步组件
    const asyncModalWithOptions = defineAsyncComponent({
        loader: () => import('./Modal.vue'),
        delay: 200,
        timeout: 3000,
        errorComponent: ErrorComponent,
        loadingComponent: LoadingComponent
    })

(4). 组件事件现在应该使用 emits 选项进行声明。

Vue 3 现在提供一个 emits 选项,和现有的 props 选项类似。这个选项可以用来定义一个组件可以向其父组件触发的事件。

Vue3中 emits选项会影响一个 监听器 被解析为 组件事件监听器 还是 原生DOM事件监听器,注意原生DOM事件存在冒泡触发机制【可通过在emits选项中添加对应的事件名避免被解析为原生DOM事件监听器】。


4. 渲染函数。
(1). 渲染函数 API 更改【此更改不会影响 <template> 用户】。

h 现在是需要从全局导入,而不是默认可作为参数传递给渲染函数。

更改了渲染函数参数,使其在有状态组件和函数组件的表现更加一致。

VNode 现在有一个扁平的 prop 结构。
示例:
    // 3.x 语法
    {
        class: ['button', { 'is-outlined': isOutlined }],
        style: [{ color: '#34495E' }, { backgroundColor: buttonColor }],
        id: 'submit',
        innerHTML: '',
        onClick: submitForm,
        key: 'submit-button'
    }
 
(2). $scopedSlots property 已移除,所有插槽都通过 $slots 作为函数暴露。
示例一:
    // 3.x Syntax
    h(LayoutComponent, {}, {
        header: () => h('div', this.header),
        content: () => h('div', this.content)
    })
    
示例二:
    //需要以编程方式引用作用域插槽时。
    
    // 2.x 语法
    this.$scopedSlots.header

    // 3.x 语法
    this.$slots.header()

(3). $listeners 被移除或整合到 $attrs。

$listeners 对象在 Vue 3 中已被移除。事件监听器现在是 $attrs 的一部分。

在 Vue 3 的虚拟 DOM 中,事件监听器现在只是以 on 为前缀的 attribute,这样它就成为了 $attrs 对象的一部分,因此 $listeners 被移除了。

示例:
    {
        text: '这是一个 attribute',
        onClose: () => console.log('close 事件被触发')
    }

(4). $attrs 现在包含 class 和 style attribute。


5. 自定义元素。
(1). 自定义元素检测现在在模板编译时执行。

检测并确定哪些标签应该被视为自定义元素的过程,现在会在模板编译期间执行,且应该通过编译器选项而不是运行时配置来配置。

(2). 特殊的 is attribute 的使用被严格限制在保留的 <component> 标签中。

为了支持 2.x 在原生元素上使用 is 的用例来处理原生 HTML 解析限制,Vue3 用 vue: 前缀来解析一个 Vue 组件。
示例:
    <table>
        <tr is="vue:blog-post-row"></tr>
    </table>


6. 其它小改变。
(1). beforeDestroy 生命周期选项被重命名为 beforeUnmount,destroyed 生命周期选项被重命名为 unmounted。

(2). Vue3中 选项式 生命周期选项 相比较 Vue2生命周期钩子 增加了 renderTracked【开发调试用,在一个响应式依赖被组件的渲染作用追踪后调用。】、renderTriggered【开发调试用,在一个响应式依赖被组件触发了重新渲染之后调用。】、serverPrefetch【SSR选项,在 组件实例在服务器上被渲染 之前调用】 三个选项。

(3). 生成 prop 默认值的工厂函数不再能访问 this。

Vue3组件接收到的原始 prop 将作为参数传递给默认函数,inject API 可以在默认函数中使用。
示例:
    import { inject } from 'vue'
    export default {
        props: {
            theme: {
                default (props) {
                    // `props` 是传递给组件的、
                    // 在任何类型/默认强制转换之前的原始值,
                    // 也可以使用 `inject` 来访问注入的 property
                    return inject('theme', 'default-theme')
                }
            }
        }
    }

(4). 自定义指令的 API 已更改为与组件生命周期一致,且 binding.expression 已移除。

Vue3自定义指令的钩子函数已经被重命名,以更好地与组件的生命周期保持一致。
示例:
    const MyDirective = {
        created(el, binding, vnode, prevVnode) {}, // 新增
        beforeMount() {},
        mounted() {},
        beforeUpdate() {}, // 新增
        updated() {},
        beforeUnmount() {}, // 新增
        unmounted() {}
    }

(5). data 选项应始终被声明为一个函数。

组件选项 data 的声明不再接收纯 JavaScript object,而是接收一个 function。

(6). 来自 mixin 的 data 选项现在为浅合并。

当合并来自 mixin 或 extend 的多个 data 返回值时,合并操作现在是浅层次的而非深层次的 (只合并根级属性)。

(7). Attribute 强制策略已更改。

移除 枚举attribute【包括 contenteditable、draggable 和 spellcheck】 的内部概念,并将这些 attribute 视为普通的非布尔 attribute。

如果值为布尔值 false,则不再移除 attribute。取而代之的是,它将被设置为 attr="false"。若要移除 attribute,应该使用 null 或者 undefined。

(8). Transition 的一些 class 被重命名。

过渡类名 v-enter 修改为 v-enter-from、过渡类名 v-leave 修改为 v-leave-from。

(9). <TransitionGroup> 不再默认渲染包裹元素。

<transition-group> 不再默认渲染根元素,但仍然可以用 tag attribute 创建根元素。

(10). 当侦听一个数组时,只有当数组被替换时,回调才会触发,如果需要在变更时触发,则必须指定 deep 选项。

换句话说,在数组被改变时侦听回调将不再被触发。要想在数组被改变时触发侦听回调,必须指定 deep 选项。

(11). 没有特殊指令的标记 (v-if/else-if/else、v-for 或 v-slot) 的 <template> 现在被视为普通元素,并将渲染为原生的 <template> 元素,而不是渲染其内部内容。

(12). 已挂载的应用不会替换它所挂载的元素,而是会作为子元素插入。

在 Vue 2.x 中,当挂载一个具有 template 的应用时,被渲染的内容会替换我们要挂载的目标元素。

在 Vue 3.x 中,被渲染的应用会作为子元素插入,从而替换目标元素的 innerHTML。

(13). 生命周期的 hook: 事件前缀改为 vue:。

在 Vue 2 中,我们可以通过事件来监听组件生命周期中的关键阶段。这些事件名都是以 hook: 前缀开头,并跟随相应的生命周期钩子的名字。

在 Vue 3 中,这个前缀已被更改为 vue:。额外地,这些事件现在也可用于 HTML 元素,和在组件上的用法一样。
示例一:
    <template>
        <child-component @vue:updated="onUpdated">
    </template>
示例二:
    <template>
        <input @vue:mounted="({ el }) => el.focus()">
    </template>
    
(14). 对于组件间的逻辑复用,推荐使用组合式 API 的组合式函数,而不是mixins。

(15). Vue3中,number 修饰符会在输入框有 type="number" 时自动启用。而Vue2中不会。


7. 被移除的 API。
(1). Vue3不再支持使用数字 (即键码) 作为 v-on 修饰符,不再支持 config.keyCodes。

从 KeyboardEvent.keyCode 已被废弃开始,Vue 3 继续支持这一点就不再有意义了。因此,现在建议对任何要用作修饰符的键使用 kebab-cased (短横线) 名称。
示例:
    <!-- Vue 3 在 v-on 上使用按键修饰符 -->
    <input v-on:keyup.page-down="nextPage">

    <!-- 同时匹配 q 和 Q -->
    <input v-on:keypress.q="quit">

(2). $on,$off 和 $once 实例方法已被移除,组件实例不再实现事件触发接口。

(3). 从 Vue 3.0 开始,过滤器 (filter)已移除,且不再支持。

(4). 对 内联模板 attribute【inline-template】的支持已被移除。

(5). Vue 3.0 中 $children 实例 property 已移除,不再支持。

(6). propsData 选项之前用于在创建 Vue 实例的过程中传入 prop,现在它被移除了。如果想为 Vue 3 应用的根组件传入 prop,请使用 createApp 的第二个参数。

(7). 已移除 $destroy 实例方法。用户不应该再手动管理单个 Vue 组件的生命周期。

(8). 已移除 全局函数 set 和 delete 以及实例方法 $set 和 $delete。基于代理的变化检测已经不再需要它们了。

  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值