对vue3的理解
2020年9月发布的正式版
vue3支持大多数的Vue2的特性
Vue中设计了一套强大的组合APi代替了Vue2中的option API,复用性更强了
更好的支持TS
最主要:Vue3中使用了Proxy配合Reflect代替了Vue2中Object.defineProperty()方法实现数据的响应式(数据代理)
重写了虚拟DOM,速度更快了
新的组件:Fragment(片段)/ Teleport(瞬移) / Suspense(不确定)
设计了一个新的脚手架工具,vite
vue3为什么可以使用多个组件,好处是什么
在vue3中:组件可以没有根标签,内部会将多个标签包含在一个Fragment虚拟元素中
好处:减少标签层级,减少内存占用
setup
- setup中的返回值是一个对象,内部的属性和方法是给html模板使用的
- setup中的对象中的方法会和data函数中的都会像中的属性合并为组件对象的方法
- setup不能是一个async函数:因为返回值不再是return的对象,而是promise,模板看不到return对象中的属性数据
【注意】 在Vue3中尽量不要混合的使用data和setup及methods和setup
参数:props 、context
props 是响应式的,当传入新的 prop 时,它将被更新。、
【注意】因为 props 是响应式的,你不能使用 ES6 解构,它会消除 prop 的响应性
如果需要解构 prop,可以在 setup 函数中使用 toRefs 函数来完成此操作
不确定的props属性,用toRef
const title = toRef(props,'title')
context 是一个普通的 JavaScript 对象,也就是说,它不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构
// 暴露三个 property export default { setup(props, context) { // Attribute (非响应式对象) console.log(context.attrs) // 插槽 (非响应式对象) console.log(context.slots) // 触发事件 (方法) console.log(context.emit) } }
访问组件的 property
执行 setup 时,组件实例尚未被创建。因此,你只能访问以下 property
props
attrs
slots
emit
setup中的this
this是undefined
setup是在beforeCreate生命周期回调之前就执行了,而且就执行一次由此可以推断setup在执行的时候,当前的组件还没有创建出来,也就意味着,组件实例对象this根本就不能使用
ref
ref是一个函数:定义一个响应式的数据,返回的是一个ref对象,对中有一个value属性,如果需要对数据进行操作,需要使用ref对象调用value属性的方式进行数据操作
html模板中是不需要使用 .value写法的
一般定义一个基本类型的响应式数据,换句话说,ref 为我们的值创建了一个响应式引用
如果用ref(对象/数组),内部会自动将对象/数组转换为reactive的代理对象
ref内部:通过给value属性添加getter和setter来实现数据的劫持
放到标签上可以用来获取dom <p ref="aaa">得到我</p>
reactive
返回一个返回的是一个proxy代理对象
reactive内部:通过Proxy来实现对对象内部所有数据的劫持,并通过Reflect操作对象内部数据
计算属性和监听属性
computed
【注意】 vue3中没有filters,可以用computed和watch代替
两种写法
只读不能修改
接受一个 getter 函数,并为从 getter 返回的值返回一个不变的响应式 ref 对象。
const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // 错误
可读可修改
使用具有 get 和 set 函数的对象来创建可写的 ref 对象。
const count = ref(1) const plusOne = computed({ get: () => count.value + 1, set: val => { count.value = val - 1 } }) plusOne.value = 1 console.log(count.value) // 0
watch
- 三个参数
- 1,可以直接写被监听的值,也可以是返回值的 getter 函数
- 2, 回调函数,有旧值和新值两个参数
- 3,一个对象(可选) {immediate: true, deep: true}
与 watchEffect 比较,watch 允许我们:
1, 懒执行副作用;
2,更具体地说明什么状态应该触发侦听器重新运行;
3,访问侦听状态变化前后的值。
监听单个数据源
const num = ref(0) watch( () => num, // 或者直接写 num // 当值为复合数据类型时这些值是响应式的,要求它有一个由值构成的副本 // 例:nums=reactive([1,2,3,4]) () => [...nums], (newValues, prevValues) => { console.log(newValues, prevValues) } )
监听多个数据源
const firstName = ref(''); const lastName = ref(''); watch([firstName, lastName], (newValues, prevValues) => { console.log(newValues, prevValues); }) firstName.value = "John"; // logs: ["John",""] ["", ""] lastName.value = "Smith"; // logs: ["John", "Smith"] ["John", ""]
watchEffect
const count = ref(0) watchEffect(() => console.log(count.value)) // -> logs 0 setTimeout(() => { count.value++ // -> logs 1 }, 100)
-----------副作用,停止侦听,清除副作用,副作用刷新时机,侦听器调试还不懂------------
爷孙级组件传递
provide 进行传递 inject 进行接收
let color = ref('red') 爷组件 provide{"color":color} 孙组件 inject('color')
响应式数据判断的方法
isRef:检测一个值是否为一个ref对象
isReactive:检测一个对象是否由reactive创建的响应式代理
isReadonly:检测一个对象是否是由readonly创建的制度代理
isProxy:检查一个对象是否是由reactive或者readonly方法创建的代理
console.log(isRef(ref())) console.log(isReactive(reactive({}))) console.log(isReadonly(readonly({}))) console.log(isProxy(reactive({}))) console.log(isProxy(readonly({})))
customRef
创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收 track 和 trigger 函数作为参数,并且应该返回一个带有 get 和 set 的对象。
<template> <input type="text" v-model="keyword" /> <h1>{{ keyword }}</h1> </template> <script> import { customRef } from 'vue' export default { setup() { // 自定义hook防抖的函数 function useDebouncedRef(value, delay = 200) { // 准备一个存储定时器的id的变量 let timeOutId return customRef((track, trigger) => { return { get() { track() return value }, set(newValue) { clearTimeout(timeOutId) timeOutId = setTimeout(() => { value = newValue trigger() return value }, delay) }, } }) } const keyword = useDebouncedRef('a11aa', 500) return { keyword, } }, } </script>