Vue2至Vue3的变化
-
v-if
和v-for
优先级已更改,但不推荐同时使用v-if
和v-for
。 -
组件事件需要在
emits
选项中声明 -
destroyed
生命周期选项被重命名为unmounted
-
beforeDestroy
生命周期选项被重命名为beforeUnmount
-
自定义指令的API已更改为与组件生命周期一致
-
新增了三个组件:
Fragment
支持多个根节点、Suspense
可以在组件渲染之前的等待时间显示指定内容、Teleport
可以让子组件能够在视觉上跳出父组件(如父组件overflow:hidden) -
新增指令
v-memo
,可以缓存 html 模板,比如 v-for 列表不会变化的就缓存,简单说就是用内存换时间。 -
用
Proxy
代替 Object.defineProperty 重构了响应式系统,可以监听到数组下标变化,及对象新增属性,因为监听的不是对象属性,而是对象本身,还可拦截 apply、has 等13种方法 -
重构了虚拟 DOM,在编译时会将事件缓存、将 slot 编译为 lazy 函数、保存静态节点直接复用(静态提升)、以及添加静态标记、Diff 算法使用 最长递增子序列 优化了对比流程,使得虚拟 DOM 生成速度提升
200%
-
支持在
<style></style>
里使用v-bind
,给 CSS 绑定 JS 变量(color: v-bind(str)
) -
新增
Composition API
可以更好的逻辑复用和代码组织,同一功能的代码不至于像以前一样太分散,虽然 Vue2 中可以用 minxin 来实现复用代码,但也存在问题,比如方法或属性名会冲突,代码来源也不清楚等 -
全局函数
set
和delete
以及实例方法$set
和$delete
移除。基于代理的变化检测已经不再需要它们了 -
毕竟 Vue3 是用
TS
写的,所以对TS
的支持度更好 -
Vue3 不兼容
IE11
-
$on
,$off
和$once
-
-
三、组合式API
- 原有的组件选项(、
computed
、methods
、 )的方式来编写组件代码通常来说是十分有效的,但是也会存在一些不好的地方,例如把原有相关的逻辑、事件、变量按照选项划分区域,这样我们就必须不断上下滚动代码寻找对应的代码块逻辑,掩盖自身原有潜在的逻辑问题,带来极大不便,如果这段业务逻辑代码并非原本人来维护,这样会导致组件内代码难以理解和阅读。 - 所以针对这类情况,Vue3提出了新的编写组织组件代码的方式——组合式API。组合式API需要一个可以实际使用的地方,那就是
setup
。 setup
触发时机在组件创建之前执行。需要注意的是,在setup中应避免使用this
,因为这个时候this的指向并不代表组件实例。setup
的调用发生在、computed
、methods
被解析之前,所以其三没办法再setup中被获取- 当然在Vue3中同样支持Option API写法进行编码,与Vue2无异,但是官方不建议这么写。
- 组合式API写法推荐
<script>
import { defineComponent, ref, onMounted } from 'vue';
export default defineComponent({
setup(){
let num = ref(0);
let fn = () => {};
onMounted(():void => {
console.log('生命周期mounted');
});
return {
num,
fn
}
}
})
</script>
- 更为简便的一种写法
<script lang='ts' setup>
import { reactive, toRefs, ref} from 'vue'
//在setup环境下组件默认引入definedComponent
let num= ref(0);
const appClick = ()=>{
console.log(num.value)
}
// 无需return
</script>
—————————————————————————————————
- 生命周期(钩子函数)
-
Option API setup beforeCreate - created - beforeMount OnBeforeMount mounted onMounted beforeUpdate onBeforeUpdate Updated onUpdated beforeUnmount onBeforeUnmount unmounted onUnmounted 组件缓存 activated onActivated 组件缓存 deactivated onDeactivated - 在Vue3中, 是在
beforeCreate
和created
生命周期钩子前运行的,因此不需要定义他们。以上这些钩子中编写的代码都应该在setup函数中进行。 -
ref、toRefs、reactive响应式和methods
-
Vue2.X中默认写在data的值,初始化组件时,内部会自动完成值的数据响应式绑定(、 绑定),但是Vue3里需要手动调用内置方法进行实现。
-
ref不仅可以用在数据响应式,还可以绑定DOM元素
-
<template> <div> <div>{{ num }}</div> <button @click="add1">num++</button> <p>-------------------------------</p> <div>{{ state.count }}</div> <button @click="add2">state.count++</button> <p>-------------------------------</p> <div>{{ count }}</div> <button @click="add3">count++</button> </div> </template> <script lang="ts"> import { defineComponent, ref, reactive, toRefs } from "vue"; export default defineComponent({ setup() { interface ObjItf { count: number; } // ref声明响应式数据,用于声明基本数据类型 let num = ref<number>(1); let obj = { count: 1, }; // reactive声明响应式数据,用于声明引用数据类型 let state = reactive<ObjItf>(obj); // toRefs解构响应式数据 let { count } = toRefs<ObjItf>(state); const add1 = (): void => { num.value++; // 注意通过ref声明的变量,所以js要修改对应的值是要通过.value访问才可以,template模板不需要通过.value访问 }; const add2 = (): void => { state.count++; // 通过reactive声明的遍历,不需要通过.value访问值 }; const add3 = (): void => { count.value++; // 通过toRefs结构的值和ref声明的变量一样,需要通过.value访问其值 }; return { num, state, count, add1, add2, add3, }; }, }); </script>
- 注意:
- 1.reactive可以传递基本数据类型和引用数据类型,基本数据类型不会被包装成响应式数据
- 2.reactive返回的响应式数据本质是Proxy对象,对象里面每一层都会被包装成Proxy对象
- 3.reactive返回的响应式数据和原始数据会相互影响
- 4.ref可以传递基础数据类型和引用数据类型。如果是基本数据类型,那么这个值保存在返回的响应式数据的
.value
上;ref声明的变量,template模板上不需要通过.value
访问。如果是引用类型,响应式数据同样在.value
上。 - 5.ref本质是将一个数据变成一个对象,这个对象具有响应式特点。
-
为什么需要toRefs和toRef?
- 和
ref
不同的是,toRef
和toRefs
两个方法,其二之中不是创造响应式,而是延续 响应式。创造响应式一般由ref和reactive来解决,而toRef和toRefs则把都对象的数据进行分解和扩散,其这个对象针对的是响应式对象(reactive)而非普通的对象。 -
watch
- 语法:
watch(监听源|[多个],(val,newVal)=>{},{immediate?:false,deep:false})
- watch写法上可以支持单个或若干个监听源,这些监听源必须只能是
getter/effect
函数,ref数据,reactive对象,或者是数组类型 -
<template> <div> {{ num }} <button @click="addNum">++</button> </div> </template> <script lang="ts" setup> import { reactive, toRefs, ref, watch } from "vue"; interface ObjItf { num: number; } let obj: ObjItf = { num: 1, }; // reactive声明响应式数据,用于声明引用数据类型 let state = reactive<ObjItf>(obj); // toRefs解构响应式数据 let { num } = toRefs<ObjItf>(state); const addNum = () => { num.value++; }; watch(num, (newVal, oldVal) => { console.log(newVal, oldVal); }); </script> <style lang="less" scoped></style>
-
watchEffect
- 它立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。
-
<template> <div>{{num}}</div> </template> <script lang="ts" setup> import { reactive, toRefs, ref, watchEffect } from "vue"; let num = ref(0); watchEffect(() => { console.log(num.value); }); setTimeout(() => { num.value++; }, 2000); </script> <style lang="less" scoped></style>
- watch和watchEffect的区别
- 两者都可监听
data
属性的变化; watch
需要明确监听哪个属性;- 而
watchEffect
会根据其中的属性,自动监听其变化。 - computed
-
<!-- --> <template> <div>{{ count }}</div> </template> <script lang="ts" setup> import { reactive, toRefs, ref, watchEffect, computed } from "vue"; let state = reactive({ num: 1, arr: [1, 54, 6, 3, 2, 3], }); let count = computed((): number => { return state.num; }); </script>
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步