Vue3新特性
-
底层响应式原理:由Vue2的数据劫持(Object.defineProperty)变成了使用代理Proxy,细致到叶子结点的每个响应式数据都有一个Proxy对象代理进行编辑,代理在修改数据的时候一定会通知视图,性能较Vue2提高了很多;
-
组合式API(compositionAPI),使组件间复用逻辑变得更方便,原理是通过组合式的hooks
组合式API的入口函数
-
setup(props,context){...}
-
setup本身类似于一个生命周期选项,执行在创建阶段之前
-
props是父组件传递过来的props
-
setup函数中拿不到组件实例this,context类似于组件实例,从其中可以解构出一些组件实例常用的属性和方法,例如:attrs、emit
生命周期
- 从vue中导入生命周期回调函数
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
} from "vue";
- 使用方式
onMounted(
// 当生命周期走到mounted,你想干嘛
()=>console.log("onMounted")
)
- 重构为可以独立调用生命周期回调配置函数,好处是将来组件可以将自己的生命周期回调逻辑“组合”到自定义hook中从而实现跨生命周期的逻辑复用
创建独立的响应式数据
ref
-
import {ref} from "vue" -
const xxRef = ref(defaultValue)申请一块内存地址,并丢入初始值 -
代码访问xxRef地址内的值:xxRef.value
-
模板访问xxRef地址内的值,代码将xxRef暴露给模板
-
在普通setup函数中暴露:return {xxRef,...}
-
在script-setup中只要将xxRef定义在代码的最顶层即默认对模板暴露
-
使用xxRef去捕获元素或模板
<p ref="xxRef">将当前P元素丢入xxRef地址内</p> -
后续使用xxRef.value即得到元素或组件的实例
-
ref通常用于创建一个独立的基本数据类型
reactive + toRefs
-
import {reactive,toRefs} from "vue" -
reactive用于创建一个响应式的对象
const state = reactive({...}) -
将state暴露给模板后,模板通过state.xxx访问state中的key-value
-
当state的key很多的时候,模板都state.xxx比较麻烦,因此我们使用toRefs将state的每个key都变为一个独立的ref
-
const {name,age} = toRefs(state)得到state.name和state.age的存放地址ref -
将state的所有key的地址/ref一次性暴露给模板
setup(){
return {
// 将对象展开为一堆key-value
...toRefs(state)
}
}
创建独立的数据侦听
computed创建独立的计算属性/二手数据
import {computed} from "vue"
const secondHandState = computed(
// 当依赖的一手数据项变化时自动回调 用于为secondHandState生成新的值
()=> state.name + state.age
)
watch创建独立的单个数据侦听逻辑
- 侦听基本数据类型
import {watch} from "vue"
watch(
// 要侦听的数据项
ageRef,
// 数据变化时的回调
(newAge, oldAge) => {
console.log("ageRef数据变化了", newAge, oldAge);
},
// 配置项
{
// 组件挂载之初就侦听一次
immediate: true,
}
);
- 侦听引用数据类型
watch(
// 要侦听的数据项通过函数闭包得到(多个组件实例相互不影响)
() => state.wife,
// 数据变化时的回调
(newValue, oldValue) => {
console.log("state.wife数据变化了", newValue, oldValue);
},
// 配置项
{
// 组件挂载之初就侦听一次
immediate: true,
// 深度侦听
deep: true,
}
);
watchEffect自动收集侦听依赖
/* 自动收集依赖项(要侦听的一手数据项) */
watchEffect(
// 副作用回调
()=>{
console.log(ageRef.value);
console.log(timeRef.value);
// 对于引用数据类型 地址不变化时侦听不到
console.log(state.wife);
}
)
强大的跨组件逻辑复用之王——自定义hook
自定义Hook的技术前提
-
vue3中响应式数据的创建是独立的
-
vue3中状态的变化侦听逻辑是独立的
-
vue3的生命周期回调配置是可以独立存在的
-
将以上内容全部组合到一个函数中,就形成了可以跨组件复用逻辑的自定义hook函数
自定义hook为何物
-
创建响应式数据的工厂函数
-
useMousePosition名字中的MousePosition就是自带变化逻辑的响应式数据
-
useCountDown名字中的CountDown就是自带变化逻辑的响应式数据
-
今后自定义hook时首先想好要复用哪些动态数据
经典案例
-
useMousePosition
-
useCountDown
script-setup语法糖
<script setup>
...
</script>
-
所有代码相当于直接写在setup函数中
-
位于代码顶层的所有变量和函数都直接对模板暴露
在script-setup中定义props,emits,provide,inject,expose
import {defineProps,defineEmits,defineExpose,provide,inject} from "vue"
// 定义属性
const props = defineProps({
name: String,
age: Number,
});
// 定义事件
const emit = defineEmits(["change", "delete"]);
const a = ref(101);
const b = 201;
const sayHello = ()=>console.log("hello from child3");
// 向外界暴露数据
defineExpose({
a,
b,
sayHello
});
// provide("location", "North Pole");
provide("geolocation", {
longitude: 90,
latitude: 135,
});
// 拿到以后即可通过 this.userGeolocation进行使用
// 接收父辈组件全局透传下来的location 为空时默认使用The Universe
const userLocation = inject("location", "The Universe");
const userGeolocation = inject("geolocation");