对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>