1.Compoisition API
Composition API字面意思是组合API,它是为了实现基于函数的逻辑复用机制而产生的,将组成组件的内容划分为各种逻辑,并将这些逻辑通过Composition Api*(组合APi)来明朗化。
2.setup函数和常用的Compoisition API
如果
setup
返回一个对象,则该对象的属性将合并到组件模板的渲染上下文中:
<template>
<div>{{ count }} {{ object.foo }}</div>
</template>
<script>
//reactive 和 ref 都是用来定义响应式数据的 reactive更推荐去定义复杂的数据类型 ref 更推荐定义基本类型
//ref 和 reactive 本质我们可以简单地理解为ref是对reactive的二次包装, ref定义的数据访问的时候要多一个.value
import { ref, reactive } from 'vue'
export default {
props: {
name: String
},
//该函数将接收到的 prop 作为其第一个参数
//context:
//上下文对象 对应之前vue2的
// context.attrs this.$attrs 组件标签上的属性(非响应式对象)
//context.slots this.$slots 插槽(非响应式对象)
//context.emit this.$emit 标签上自定义的触发事件(方法)
//context.emit('自定义事件名',参数)
//attr ->> Noe-props属性 <child app="app"/> 不用props接收 就会被attrs接收到
//slots ->> <child>parent</child> ->> slots.default()获取到 ()=> h('div',{},slots.default())
//setup函数在created生命周期之前就会触发 所以里面不能用this对象了
handleChange(){
alert('change')
}
template: `<child @change="handleChange"></child>`
setup(props,context,toRefs,readonly,toRef) {
// ref 一般是简单变量使用
const count = ref(0)
// reactive一般是复杂机构的 如 对象 数组等使用
const object = reactive({ foo: 'bar' })
//用toRefs解构出来的变量是响应式的
// toRefs解构出来的样子从propxy({name:'dell'}) 变成{name:proxy({value:'dell'})}
const {name}=toRefs(object )
//只读的 不能修改
const copyName = readonly(object );
//从object里面取 如果没有 就是空数据
const age = toRef(object , "age");
// 暴露到template中
return {
count,
object
}
}
}
app.component("child", {
template: `<div @click="handleClick">child</div>`,
setup(props, context) {
const { attrs, slots, emit } = context;
function hanldeClick() {
emit("change");
}
return { hanldeClick };
},
});
</script>
3.computed方法
const app = Vue.createApp({
setup() {
const { ref, computed } = Vue;
const count = ref(0);
const handleClick = () => {
count.value += 1;
};
const countAddFive = computed(() => {
return count.value + 5;
});
// 类似ES6的proxy 可以设置set 和 get操作时的拦截器
const countAddFive = computed({
get: () => {
return count.value + 5;
},
set: (param) => {
count.value = param - 5;
},
});
setTimeOUt(()=>{
countAddFive = 100
},1000)
return { count, handleClick, countAddFive };
},
template: `
<div>
<span @click="handleClick">{{count}}</span> -- {{countAddFive}}
</div>
`,
});
4.watch和watchEffect
setup() {
const { ref, computed, watch, reactive, toRefs, watchEffect } = Vue;
const name = ref("hzx");
//参数可以拿到原始的和现在的值
//具备一定的惰性lazy 首次页面展示的时候不会执行
//立即执行 无惰性 加入immediate选项立即执行
watch(name, (currentValue, preValue) => {
console.log(currentValue,preValue)
}, { immediate: true });
}
//使用比较多的是异步请求
const stop = watchEffect(() => {
// nameObj.name 只要检测到对数据有依赖 就会有侦听
console.log(nameObj.name)
setTimeout(() => {
// 停止侦听 watch和这里的方法一样
stop();
}, 5000);
});
5.setup中的生命周期函数
const app = Vue.createApp({
setup() {
const {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnMount,
onUnmounted,
onRenderTracked,
onRenderTriggered,
} = Vue;
onBeforeMount(() => {
console.log("onBeforeMount");
});
onMounted(() => {
console.log("onMounted");
});
onBeforeUpdate(() => {
console.log("onBeforeUpdate");
});
onUpdated(() => {});
onRenderTracked(() => {
//页面渲染之后 重新收集响应式依赖
});
onRenderTriggered(() => {
// 页面再次渲染 会执行
});
},
template: `
<div>
Hello World
</div>
`,
});
6.setup中的provide和ref(获得真实的DOM)
const app = Vue.createApp({
setup() {
const { ref, provide, readonly } = Vue;
const name = ref("dell");
// 传递给子组件的数据是只读的
provide("name", readonly("dell"));
// 提供改变name的方法
provice("changeName", (value) => {
name.value = value;
});
},
template: `
<div>
<child/>
</div>
`,
return {name,handleClick}
});
app.component("child", {
setup() {
const { inject } = Vue;
// 默认值hello
const name = inject("name", "hello");
const changeName = inject("changeName");
const handleClick = () => {
changeName("lee");
};
return { name, handleClick };
},
template: `<div @click="handleClick">child</div>`,
});
//获取真实的DOM
const app = Vue.createApp({
setup() {
//获取这个DOM节点
const { ref } = Vue;
const hello = ref(null);
onMounted(() => {
//获取这个DOM节点
console.log(hello.value);
});
return { hello };
},
template: `
<div>
//获取这个DOM节点
<div ref="hello">helloworld</div>
</div>
`,
});