Setup 钩子是在组件中使用组合式 API 的入口,通常只在以下情况下使用:
1.需要在非单文件组件中使用组合式 API 时。
2.需要在基于选项式 API 的组件中集成基于组合式 API 的代码时。
注意:setup函数里的this不是vue对象。
setup函数的返回值:
1.会挂载在vue对象上
2.可以在组件的任何地方使用(如:模板,其它配置项)
slot槽口/插槽:
插槽用来混合父组件与子组件自己的模板(就是可以在组件被调用的时候向其内部插入新的dom节点)
组件的内容就是标签的innerHTML。vue.js里使用Slot(插槽)分发内容。
props用来处理标签的属性 ,slot用来处理标签的内容。 将父组件的内容(DOM)放到子组件指定的位置叫作内容分发。
单个插槽(基本插槽)
就是在你想插入新内容的组件中 放置一个
具名插槽(多个插槽需要使用名字)
如果父级给子级传来了好多DOM(HTML元素),而且需要把不同的DOM放在子组件不同位置时,就需要给 slot起名字,这就是具名插槽。slot元素可以用一个特殊的属性name 来配置如何分发内容。
子组件:
父组件:
a.必须用template包裹,
b.v-slot:插槽名
传给槽口的内容
c.v-slot:插槽名可以简写为 #槽口名
作用域插槽
父组件模板的内容在父组件作用域内(父组件对应的对象的作用域)编译;子组件模板的内容在子组件作用域内编译
1.在子组件中定义插槽名,约定key传递数据给父组件
2.在父组件中通过v-slot:插槽名="对象
作用:定义一个响应式的数据
功能:接受值,返回一个响应式的、可更改的 ref 对象,ref对象只有一个属性:value
。value属性保存着接受的值。
注意:
使用ref对象:模板上不需要写 .value 属性(会自动解构),在js中,使用 .value 来完成数据的读写。
ref接收基本类型和引用类型
基本类型的数据:响应式依然是靠object.defineProperty()的get和set完成
引用类型的数据:内部求助了一个Vue3的新函数——reactive函数
作用:定义一个对象类型的响应式数据(基本类型别用他,用ref)
功能:接受一个对象,返回一个对象的响应式代理(proxy)。返回的对象以及其中嵌套的对象都会通过 ES Proxy 包裹,因此不等于源对象,建议只使用响应式代理,避免使用原始对象。
1.定义角度:
ref定义内置基本类型,reactive定义对象类型
ref也可以定义对象或者数组,内部原理是还是通过reactive转为代理对象
2.原理:
ref:是通过Object.defineProperty()的get和set实现响应式的
reactive通过proxy
3.使用:
ref:模板上不需要value,但是脚本中需要
reactive:均不需要
功能:接受一个对象 (不论是响应式还是普通的) 或是一个 ref,返回一个原值的只读代理。
只读代理是深层的:对任何嵌套属性的访问都将是只读的。它的 ref 解包行为与 reactive()
相同,但解包得到的值是只读的。
实现原理:
1.通过Proxy(代理):拦截对象中任意属性的变化,包括:属性的读写、属性的添加、属性的删除等等
2.通过Reflect(反射):对源对象的属性进行操作
let person = { name: '张三', age: 18 } const p = new Proxy(person, { // 拦截读取属性值 get(target, propName) { return Reflect.get(target, propName) }, // 拦截设置属性值或添加新属性 set(target, propName, value) { Reflect.set(target, propName, value) }, // 拦截删除属性 deleteProperty(target, propName) { return Reflect.deleteProperty(target, propName) } })
setup执行的时机
在beforeCreate之前执行一次,this是undefined。
setup的参数
props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性
ocontext: 上下文对象
attrs:值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性,相当于this.$attrs 。
slots:收到的插槽内容,相当于this.$slots 。
emit:分发自定义事件的函数,相当于this.$emit 。
与vue2.x中computed配置功能一样
写法:
setup() {
let person = reactive({
FirstName: "张",
LastName: "三",
});
// 计算属性:简写
person.fullName = computed(() => {
return person.FirstName + "-" + person.LastName;
});
// 计算属性:完整写法
person.fullName = computed({
get() {
return person.FirstName + "-" + person.LastName;
},
set(value) {
const nameArr = value.split("-");
person.FirstName = nameArr[0];
person.LastName = nameArr[1];
},
});
return {
person,
};
},
与vue2.x中的watch配置功能一致
两个小坑:
监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监听
监视reactive定义的响应式数据中某个属性时:deep配置有效
情况一:监视ref所定义的一个响应式数据
watch(sum, (newValue, oldValue) => {
console.log(newValue, oldValue);
},{immediate:true,deep:true});
情况二:监视ref所定义的多个响应式数据
watch([sum, msg],(newValue, oldValue) => {
console.log(newValue, oldValue);
},{ immediate: true, deep: true });
情况三:监听reactive所定义的一个响应式数据的全部属性,
注意:1.此处无法正确的获取oldAalue
2.强制开启了深度监听(deep配置无效)
watch(person, (newValue, oldValue) => {
console.log(newValue, oldValue);
});
情况四:监听reactive所定义的一个响应式数据的某个属性,
watch(() => person.name,(newValue, oldValue) => {
console.log(newValue, oldValue);
});
情况五:监听reactive所定义的一个响应式数据的某些属性,
watch([() => person.name, () => person.age], (newValue, oldValue) => {
console.log(newValue, oldValue);
});
特殊情况
watch(() => person.job,(newValue, oldValue) => {
console.log(newValue, oldValue);
},{ deep: true });// 此处由于监视的是reactive所定义的对象中的某个属性,所以deep配置有效
watch的套路是:既要指明监视的属性,也要指明监视的回调
watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性
watchEffect有点像computed:
但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值
而watchEffect更注意的是过程(回调函数的函数体),所以不用写返回值
注意:watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调
什么是hook?——本质是一个函数,把setup函数中使用的Composition API进行了封装
类似于vue2.x中的mixin
自定义hook的优势:复用代码,让setup中的逻辑更清晰易懂
作用:创建一个ref对象,其value值指向另一个对象中的某个属性
语法:const name = toRef(person,'name')
应用:要将响应式对象中的某个属性单独提供给外部使用时
扩展:toRefs与toRef功能一致,但可以批量创建多个ref对象,语法:toRefs(person)