Advertisement

Vue3对比Vue2的一些差异及特性

阅读量:

1. Vue3和Vue2的风格对比

Vue2一般称之为选项式(Options)API

Vue3一般称之为组合式(Composition)API

如图所示 :

2. Vue2选项式和Vue3组合式API的关系

组合式API的目的是增强,不是取代选项式API,vue3对两种API都支持

简单的场景使用选项式API更加简单方便

需要强烈支持TS的项目首选组合式API

需要大量逻辑复用的场景首选组合式API

3. Vue3对比Vue2的一些注意事项

Vue 2 中的 template 标签仅允许包含一个根元素,在对 template 进行操作时,请确保将其中的 root 元素直接地移动至 #app 位置

Vue3中没有该约束允许放置任意多个根元素。将template中的所有根元素作为appendChild的方式添加到#app中而不是将其替换为其他内容。

vue2 在 methods 中访问 data 的数据都要加 this, 在 template 中可以不用

vue3 使用 ref 声明的数据, 访问时都需要加 .value, 在 template 中可以不用

vue3中compositionAPI 的数据不在 data 中声明,而是在新钩子函数setup()中声明

在 setup 函数中要返回一个对象, 对象中的成员就可以直接在 template 中使用

4. 在 setup 函数中使用生命周期钩子函数

使用步骤

先从vue中导入以on打头的生命周期钩子函数

在setup函数中调用生命周期函数并传入回调函数

生命周期钩子函数可以调用多次

示例:

复制代码
 <template>

    
   <div id="dd"></div>
    
 </template>
    
  
    
 <script>
    
 // 1. 导入 onMounted 函数
    
 // onCreated 没有
    
 import { onMounted, onBeforeMount  } from "vue";
    
 export default {
    
   // Vue 2 生命周期回顾:
    
   // 初始化阶段: beforeCreate created 只执行一次
    
   // 挂载阶段: beforeMount mounted 只执行一次
    
   // 更新阶段: beforeUpdate updated 零次或 N 次
    
   // 销毁阶段: beforeDestroy destroyed 只执行一次
    
   setup() {
    
     // let dd = document.querySelector('#dd')
    
     // console.log(dd)
    
     // 如何在 setup 中使用生命周期的钩子函数?
    
     // 2. 在 setup 中调用 onMounted
    
     // 参数: 回调函数, 在 mounted 生命周期时执行
    
     onMounted(() => {
    
       let dd = document.querySelector("#dd");
    
       console.log(dd);
    
       console.log("onMounted 了");
    
     });
    
     onMounted(() => {
    
       console.log("on 又 Mounted 了");
    
     });
    
  
    
     onBeforeMount(() => {
    
       console.log('onBeforeMount 了')
    
     })
    
  
    
     // 注意啦: vue 中没有提供初始化阶段的两个钩子函数: onBeforeCreate onCreated
    
     // 因为 Vue3 认为这两个阶段要做的事情, 都可以在 setup 里面直接做
    
     // console.log(onCreated)
    
     // onCreated(() => {
    
     //   console.log('onCreated 了')
    
     // })
    
   },
    
   mounted() {
    
     console.log("mounted 生命周期钩子函数");
    
   }
    
 };
    
 </script>

5. Vue2和Vue3的生命周期对比

选项式API下的生命周期函数使用 组合式API下的生命周期函数使用
beforeCreate 不需要(直接写到setup函数中)
created 不需要(直接写到setup函数中)
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeDestroy Vue 3: beforeUnmount onBeforeUnmount
destroyed Vue 3: unmounted onUnmounted

6. 父子通信

在vue3的组合式API框架内,默认的父子组件连接方式一致。其核心理念仍然是:父子组件之间的数据传递主要依赖prop属性实现,默认情况下无状态事件参与。

实现步骤

setup函数接受两个关键输入变量:props和context。其中,props用于表示状态信息,而context则包含环境配置。

props被视为一个对象,在其内部整合了来自父组件的所有prop数据。context对象则包括了attrs、slots以及emit属性。值得注意的是,在context中定义的emit特性能够引发生态事件并实现子组件到父组件的数据交互。

示例:

Father.vue

复制代码
 <template>

    
   <Son
    
     msg="这是爸爸给你的消息"
    
     :title="title"
    
     :list="list"
    
     @getValue="getValueHandler"
    
   ></Son>
    
 </template>
    
  
    
 <script>
    
 import { ref } from "vue";
    
 // 父子通信: 父传子
    
 // 1. 父组件中给子组件传递数据, 属性绑定
    
 // 2. 在子组件中定义 props 接收并使用
    
 // props 特点: 单向数据流, 单向下行绑定(父亲变了儿子会同步, 但儿子改数据 老子不认)
    
 // 如果传入的是引用数据类型, 修改对象的属性是可行的, 但是 ESLint 默认会检查并报错, 所以需要单独配置或关闭 ESLint
    
  
    
 // 父子通信: 子传父
    
 // 1. 父组件中给子组件自定义一个事件
    
 // 2. 子组件在合适的时机触发事件并传递数据
    
 import Son from "./components/Son.vue";
    
 export default {
    
   components: {
    
     Son,
    
   },
    
   setup() {
    
     const title = ref("这是爸爸的title");
    
  
    
     function getValueHandler(value) {
    
       console.log('收到儿子的数据:', value)
    
     }
    
  
    
     const list = ref([1, 2, 3]);
    
     return { title, list, getValueHandler };
    
   },
    
 };
    
 </script>

Son.vue

复制代码
 <template>

    
   <div>
    
     <p>这里是子组件</p>
    
     <p>收到父组件的msg: {{ msg }}</p>
    
     <p>收到父组件的title: {{ title }}</p>
    
     <button @click="title = '改成儿子的title'">点我修改爸爸的title</button>
    
     <ul>
    
       <li v-for="(item, index) in list" :key="index">{{ item }}</li>
    
     </ul>
    
     <button @click="list.push(4)">点我往list中加数据</button>
    
     <hr>
    
     <button @click="sendValue">点我向爸爸发射消息</button>
    
   </div>
    
 </template>
    
  
    
 <script>
    
 export default {
    
   props: {
    
     // 这里定义的是父组件要传递的数据, 必须在这里定义
    
     msg: String,
    
     title: String,
    
     list: Array
    
   },
    
   // setup 钩子函数中有两个参数:
    
   // 参数1: props 父组件传过来的数据都会挂载到这个对象上
    
   // 参数2: context 上下文对象, 有一些全局的实例方法, 例如 emit slots attrs
    
   // setup(props, context) {
    
   setup(props, { emit }) {
    
     // 以前使用 props 数据: this.msg
    
     // 现在没有 this 了, 如果要在 setup 中使用 props 的数据, 则需要接受第一个参数: props
    
     // console.log(props)
    
     // console.log(context)
    
     // this // 没有 this
    
     function sendValue() {
    
       // 在此处触发自定义事件, 携带数据给父组件
    
       // 这里的 this 是指 setup 返回的对象, 所以没有办法调用 $emit 函数
    
       // 故而无法在此处使用 this.$emit() 触发事件, 怎么办呢?
    
       // console.log(this.$emit) 
    
       // 参数1: 事件名
    
       // 参数2~n: 要传递的参数
    
       emit('getValue', '这是儿子孝敬您的数据')
    
       // 为什么 Vue2 的实例方法都是 $ 开头? 
    
       // 因为 Vue2 设计时所有的方法都放到原型上
    
       // data 和 methods 的成员也会被挂载到对象本身 this.msg
    
       // 如果原型上的成员不用 $ 开头, 很容易命名冲突, 命名冲突之后的结果
    
       // this.$set this.$nextTick() this.$emit() this.$mount()
    
       // Vue3 就没有这样设计了, 以上下文对象的形式暴露给用户使用, compositionAPI设计的出现, 让我们更少的依赖 data 和 methods 了
    
     }
    
     return {sendValue}
    
   }
    
 };
    
 </script>

7. provide 和 inject

通常通过props实现组件之间数据的传递。然而,在嵌入层次较多的情况下,默认逐层向下传播会变得相对复杂。借助提供(provide)与注入(inject)功能的协同工作特性,则能够便捷地实现从顶层组件向任意层级下的组件高效传输数据。

实现步骤

顶层组件在setup方法中使用provide函数提供数据

provide('key',数据)

任何底层组件在setup方法中使用inject函数获取数据

const data = inject('key')

示例:

App.vue

复制代码
 <template>

    
   <Father></Father>
    
   <button @click="msg = '在 App 中修改的新数据'">在 App 中修改数据</button>
    
 </template>
    
  
    
 <script>
    
 // 目标: 从 App 中将数据传递给 Son
    
 // 使用 provide 和 inject 实现
    
 // 1. 在 App 中导入 provide 函数
    
 // 2. 在 setup 中调用 provide 函数提供数据
    
 // 3. 在 Son 中导入 inject 函数
    
 // 4. 在 setup 中调用 inject 函数获取数据
    
 import Father from './components/Father.vue'
    
 import { provide, ref } from 'vue'
    
 export default {
    
   components: {
    
     Father
    
   },
    
   setup() {
    
     // 参数1: 字符串, key, 提供的数据标识
    
     // 参数2: 数据
    
     // let msg = '这是 App 的数据' // 静态数据
    
     const msg = ref('这是 App 的数据')  // 响应式的数据
    
     // provide('msg', msg.value) // .value 表示将数据取出来后传递给子组件, 丧失了响应式的特性, 如果希望数据也是响应式的传递, 则不能加 .value
    
     // 如果不加 .value 表示传递对象, 加了就是获取静态数据传递过去
    
     provide('msg', msg)
    
  
    
     return {
    
       msg
    
     }
    
   }
    
 };
    
 </script>

Father.vue

复制代码
 <template>

    
   这是 Father 组件
    
   <Son></Son>
    
 </template>
    
  
    
 <script>
    
 import Son from './Son.vue'
    
 export default {
    
   components: {
    
     Son
    
   }
    
 }
    
 </script>

Son.vue

复制代码
 <template>

    
   <div>
    
     这是 Son 组件
    
     <p>这是收到的数据: {{ msg }}</p>
    
   </div>
    
 </template>
    
  
    
 <script>
    
 import { inject } from 'vue';
    
 export default {
    
   setup() {
    
     // 参数: 要获取的数据标识 key
    
     // 返回值: 数据
    
     let msg = inject('msg')
    
     return {
    
       msg
    
     }
    
   }
    
 };
    
 </script>

8. TemplateRef

在模板中使用ref,我们都很清楚,它一般有三种使用场景

ref + 普通dom标签 获取真实dom对象

this.$refs.box

ref + 组件标签 获取组件实例对象

this.$refs.form.validate()

ref + v-for 获取由dom对象(实例对象)组成的数组 (不经常使用)

实现步骤

使用ref函数传入null创建 ref对象 = > const hRef = ref(null)

在模板中,通过将ref属性设置为1生成的ref对象名称实现了与

元素之间的关联。

hRefreturn出去

使用 = > hRef.value

示例:

复制代码
 <template>

    
   <!-- Vue2 的做法 -->
    
   <!-- <p ref="cuteP">这是一个可爱的 p</p>
    
   <Father ref="dad"></Father> -->
    
   
    
   <!-- 3. 在需要获取对象的标签上使用 ref 绑定返回的数据 -->
    
   <p ref="cp">这是一个可爱的 p</p>
    
   <Father ref="father"></Father>
    
 </template>
    
  
    
 <script>
    
 import { onMounted, ref } from 'vue';
    
 // 目标: 在 setup 函数中使用 ref 获取原生 DOM 对象
    
 import Father from './components/Father.vue'
    
 export default {
    
   components: {
    
     Father
    
   },
    
  
    
   setup() {
    
     // 1. 使用 ref 创建一个空的数据 用于后面产生关联
    
     const cp = ref(null)
    
     const father = ref(null)
    
  
    
     // 此时无法获取, 都是 null, 因为 setup 在 beforeCreate 之前执行
    
     console.log(cp.value)
    
     console.log(father.value)
    
  
    
     onMounted(() => {
    
       // 4. 在合适的时机使用 数据.value 即可访问原生 DOM
    
       // 在原生 DOM 挂载完毕后执行
    
       console.log(cp.value)
    
       console.log(father.value)
    
     })
    
  
    
     // 2. 将数据返回出去供 template 使用
    
     return {
    
       cp,
    
       father
    
     }
    
   }
    
  
    
   // mounted() {
    
   //   // Vue2 的做法: 必须在 mounted 中获取
    
   //   console.log(this.$refs.cuteP)
    
   //   console.log(this.$refs.dad)
    
   // }
    
 };
    
 </script>

9. Vue3的非兼容语法

Vue3遵循Vue2的大部分语法支持其功能实现,并且也引入了一些破坏性更新需要特别需要注意

具体实现方式删除(现有实现模式不再适用,可以选择调用第三方插件来完成功能)

Event Bus

1. A Vue instance of eventBus is created via `Vue.prototype.eventBus = new Vue(). 2\. Within a component receiving data, call this.eventBus.on('get-msg', (msg) => {})`. 3\. Within a component sending data, invoke `this.eventBus.emit('get-msg', '传递的数据')`.
4. By default, event bus functionality is unsupported in Vue 3; third-party plugins are required for emulation.

2. 移除过滤器filter (在插值表达式中无法继续使用过滤器可用methods来代替)

filter过滤器
例如:字符串的格式化 方法 接收原字符串 返回格式化之后的字符串

{{ msg | formatMsg }}

vue3直接移除了该语法 可以直接使用methods替代

{{ formatMsg('this is msg') }} // 渲染的结果是函数return值
methods:{
formatMsg(msg){
return msg + 'zs'
}
}

3. sync语法移除 (和v-model语法合并)

同步机制
配置项设置为elementUI指向Dialog,并启用visible属性以显示showFlag状态
其主要作用包括简化父级与子级之间的通信流程,并支持自定义事件的触发
同步机制与v-model实现绑定的核心

全部评论 (0)

还没有任何评论哟~