Composition API的使用

一、setup函数的使用

  • 一个组件选项,在组件被创建之前props 被解析之后执行。
  • 它是组合式 API 的入口。
const app = Vue.createApp({
    template: `
        <div @click=handleClick>{{message}}</div>
    `,
    setup(props, context) {
        // return 中返回的属性可以在template中使用
        return {
            message: 'hello',
            handleClick: () => {
                console.log(666);
            }
        }
    }
});

二、ref、reactive响应式引用的用法和原理

  • 原理:通过 proxy 对数据进行封装,当数据变化时,触发模板等内容的更新。

1. ref 的使用

  • ref 处理基础类型的数据。
const app = Vue.createApp({
    template: `
        <div>{{name}}</div>
    `,
    setup(props, context) {
        // 引入 ref
        const { ref } = Vue;
        // 'hy' 变成 proxy({value: 'hy'}) 这样的一个响应式引用
        let name = ref('hy');
        setTimeout(() => {
            name.value = 'hy666'
        }, 2000);
        return { name };
    }
});

2. reactive 的使用

  • reactive 处理非基础类型的数据。
const app = Vue.createApp({
    template: `
        <div>{{nameObj}}</div>
    `,
    setup(props, context) {
        // 引入 reactive
        const { reactive } = Vue;
        // {name: 'hy'} 变成 proxy({name: 'hy'}) 这样的一个响应式引用
        const nameObj = reactive({name: 'hy'})
        setTimeout(() => {
            nameObj.name = 'hy666'
        }, 2000);
        return { nameObj };
    }
});

3. readonly  的使用

  • 接受一个对象 (响应式或纯对象) 或 ref 并返回原始对象的只读代理
  • 只读代理是深层的:任何被访问的嵌套 property 也是只读的,修改时会报警告。
  • 注意:使用 vue3.2.23 版本时,没有警告弹出,可以选择其它版本。
const app = Vue.createApp({
    template: `
        <div>{{myArray}}--{{copyMyArray}}</div>
    `,
    setup(props, context) {
        // 引入 readonly
        const { reactive, readonly } = Vue;
        const myArray = reactive([123]);
        const copyMyArray = readonly(myArray);
        setTimeout(() => {
            myArray[0] = 666;
            copyMyArray[0] = 777;
        }, 2000);
        return { myArray, copyMyArray };
    }
});

4.  toRefs 的使用

  • 将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 ref
  • 即: 将 proxy({ name: 'hy' }) 转化为 { name: proxy({ value: 'hy' }) }
const app = Vue.createApp({
    template: `
        <div>{{name}}</div>
    `,
    setup(props, context) {
        // 引入 toRefs
        const { reactive, toRefs } = Vue;
        const nameObj = reactive({ name: 'hy' });
        setTimeout(() => {
            nameObj.name = 'hy6666';
        }, 2000);
        const { name } = toRefs(nameObj);
        console.log(name);
        return { name };
    }
});

三、toRef 以及 context 参数

1. toRef 的使用

  • 可以用来为源响应式对象上的某个 property 新创建一个 ref
  • 即使源 property 不存在,toRef 也会返回一个可用的 ref。
const app = Vue.createApp({
    template: `
        <div>{{age}}</div>
    `,
    setup(props, context) {
        // 引入 toRef
        const { reactive, toRef } = Vue;
        const nameObj = reactive({ name: 'hy' });
        // 注意接收时不需要解构
        const age = toRef(nameObj, 'age');
        setTimeout(() => {
            age.value = 28;
            console.log(age);
        }, 2000);
        return { age };
    }
});

2. context 参数的使用

  • 传递给 setup 函数的第二个参数是 context
  • context 是一个普通 JavaScript 对象,暴露了其它可能在 setup 中有用的值:attrs、slots、emit 
  • attrs:Attribute (非响应式对象,等同于 $attrs)。
const app = Vue.createApp({
    template: `<child app='app'/>`
});
app.component('child', {
    setup(props, context) {
        const { attrs, slots, emit } = context;
        console.log(attrs); // None-props 属性
        return { attrs }
    },
    template: `<div>{{attrs.app}}</div>`
});
  • slots:插槽 (非响应式对象,等同于 $slots)。
  • $slots:用来以编程方式访问通过插槽分发的内容。每个具名插槽都有其相应的 property (例如:v-slot:foo 中的内容将会在 this.$slots.foo() 中被找到)。default property 包括了所有没有被包含在具名插槽中的节点,或 v-slot:default 的内容。
const app = Vue.createApp({
    template: `<child>hello</child>`
});
app.component('child', {
    setup(props, context) {
        const { h } = Vue;
        const { attrs, slots, emit } = context;
        // slots.default() 返回的是一个虚拟DOM节点
        console.log(slots.default());
        return () => h('div', {}, slots.default());
    },
});
  • emit:触发事件 (方法,等同于 $emit)。
const app = Vue.createApp({
    methods: {
        handleChange() {
            console.log('change');
        }
    },
    template: `<child @change='handleChange'/>`
});
app.component('child', {
    template: `<div @click='handleClick'>hello</div>`,
    setup(props, context) {
        const { attrs, slots, emit } = context;
        // 点击触发 change 事件
        function handleClick() { emit('change'); }
        return { handleClick };
    },
});

四、computed方法生成计算属性

1. 接受一个回调函数

// computed计算属性
const app = Vue.createApp({
    setup() {
        const { ref, computed } = Vue;
        const count = ref(0);
        const handleClick = () => {
            count.value += 1;
        }
        const countAddSix = computed(() => {
            return count.value + 6;
        })
        return { count, handleClick, countAddSix };
    },
    template: `
        <div @click='handleClick'>
            {{count}}--{{countAddSix}}
        </div>
    `
});

2. 接受一个具有 get 和 set 函数的对象

// computed计算属性
const app = Vue.createApp({
    setup() {
        const { ref, computed } = Vue;
        const count = ref(0);
        const handleClick = () => {
            count.value += 1;
        };
        const countAddSix = computed({
            get: () => {
                return count.value + 6;
            },
            set: val => {
                count.value = val - 6;
            }
        });
        setTimeout(() => {
            countAddSix.value = 100;
        }, 1000)
        return { count, handleClick, countAddSix };
    },
    template: `
        <div @click='handleClick'>
            {{count}}--{{countAddSix}}
        </div>
    `
});

五、watch 和 watchEffect 的使用和差异性

1. watch 的使用

  • 具备一定的惰性(第一次不执行)。
  • 参数可以拿到原始值和当前值。
  • 可以侦听多个数据的变化,用一个侦听器承载。
const app = Vue.createApp({
    setup() {
        const { reactive, watch, toRefs } = Vue;
        const nameObj = reactive({
            name: '小吴',
            engName: 'hy'
        });
        watch(
            [() => nameObj.name, () => nameObj.engName],
            ([curName, curEngName], [preName, preEngName]) => {
                console.log(curName, preName, '---', curEngName, preEngName);
            }
        );
        setTimeout(() => {
            nameObj.name = '小豪';
            nameObj.engName = 'xh';
        }, 1000);
        const { name, engName } = toRefs(nameObj);
        return { name, engName };
    },
    template: `
        <div>
            name: {{name}}--engName: {{engName}}
        </div>
    `
});

2. watchEffect  的使用

  • 立即执行,没有惰性。
  • 不需要传递侦听的内容,会自动感知代码依赖。
  • 不需要传递很多参数,只要传递一个回调函数。
  • 不能获取之前数据的值。
const app = Vue.createApp({
    setup() {
        const { reactive, watch, watchEffect, toRefs } = Vue;
        const nameObj = reactive({
            name: '小吴',
            engName: 'hy'
        });
        watchEffect(()=>{
            console.log(`${nameObj.name}---${nameObj.engName}`);
        });
        setTimeout(() => {
            nameObj.name = '小豪';
            nameObj.engName = 'xh';
        }, 1000);
        const { name, engName } = toRefs(nameObj);
        return { name, engName };
    },
    template: `
        <div>
            name: {{name}}--engName: {{engName}}
        </div>
    `
});

六、生命周期函数的新写法

  • onRenderTracked: 第一次渲染时收集响应式依赖。
  • onRenderTriggered: 每次触发页面重新渲染时自动执行。
const app = Vue.createApp({
    setup() {
        const {
            ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onRenderTracked, onRenderTriggered } = Vue;
        const name = ref('hy');
        onBeforeMount(() => {
            console.log('onBeforeMount');
        });
        onMounted(() => {
            console.log('onMounted');
        });
        onBeforeUpdate(() => {
            console.log('onBeforeUpdate');
        });
        onUpdated(() => {
            console.log('onUpdated');
        });
        onBeforeUnmount(() => {
            console.log('onBeforeUnmount');
        });
        onUnmounted(() => {
            console.log('onUnmounted');
        });
        onRenderTracked(() => {
            console.log('onRenderTracked');
        });
        onRenderTriggered(() => {
            console.log('onRenderTriggered');
        });
        setTimeout(() => {
            name.value = 'xh';
        }, 1000);
        return { name };
    },
    template: `
        <div>
            name: {{name}}
        </div>
    `
});
setTimeout(() => {
    app.unmount();
}, 2000);

七、provide、inject 以及模板引用的用法

1. provide、inject  的使用

  • 父子组件间的内容传递:
// provide、inject
const app = Vue.createApp({
    setup() {
        const { ref, provide, readonly } = Vue;
        const name = ref('hy');
        // 1.key, 2.value
        provide('name', readonly(name));
        provide('changeName', (value) => {
            name.value = value
        });
    },
    template: `
        <child/>
    `
});
app.component('child', {
    setup() {
        const { inject } = Vue;
        // 1.key, 2.默认值
        const name = inject('name', 'hello');
        const changeName = inject('changeName');
        const handleClick = () => {
            changeName('xh');
        };
        return { name, handleClick };
    },
    template: `
        <div @click='handleClick'>{{name}}</div>
    `
});

2. 模板引用

  • 通过模板引用可以获取到真实的dom元素节点。
// CompositionAPI 的语法下,获取真实的 DOM 元素节点
const app = Vue.createApp({
    setup() {
        const { ref, onMounted } = Vue;
        const hello = ref(null);
        onMounted(() => {
            console.log(hello.value);
        });
        return { hello };
    },
    template: `
        <div ref="hello">hello world</div>
    `
});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值