vue3新特性

122 阅读4分钟

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");