Vue 学习笔记(下)

作者: ygqygq2 分类: 开发 发布时间: 2022-07-22 18:23

1. 混入 Mixin

基本用法:

    const myMixin = {
        data() {
            return { number: 2 }
        }
    }

    const app = Vue.createApp({
        data() {
            return { number: 1 }
        },
        mixins: [myMixin],
        template: `
        
{{ number }}
` }); const vm = app.mount('#root');
  • 组件 data, methods 优先级高于 mixin data, methods 优先级
  • 生命周期函数先执行 mixin 里的,再执行组件里的
  • 组件中的自定义属性优先级高于 mixin 中的属性优先级
  • 默认 mixin 是局部的,需要声明注入,全局 mixin 直接定义在 app 中,不需要明确注入
  • app.config.optionMergesrategies.number 定义 mixin 属性优先级
    const myMixin = {
        number: 1
    }

    const app = Vue.createApp({
        mixins: [myMixin],
        number: 2,
        template: `
        
{{ this.$options.number }}
` }); app.config.optionMergeStrategies.number = (mixinVal, appValue) => { return mixinVal || appValue; } const vm = app.mount('#root');

2. 自定义指令 directives

其支持各种生命周期函数

    const directives = {
        focus: {
            mounted(el) {
                el.focus();
            }
        }
    }

    const app = Vue.createApp({
        directives: directives,
        template: `
        
` }); const vm = app.mount('#root');

使用数据控制 directive





    
    
    
    directives
    
    

3. 传送门 teleport

默认 html dom 是层层嵌套,teleport 可以把组件里的 dom 元素直接传送到其它位置进行展示。





    
    
    
    传送门
    
    

4. render 函数

template -> render -> h -> 虚拟 DOM(JS对象)-> 真实 DOM -> 展示页面上

    const app = Vue.createApp({
        template: `
        
            hello world
        
        `
    });

    app.component('my-title', {
        props: ['level'],
        render() {
            const { h } = Vue;
            return h('h' + this.level, {}, this.$slots.default());
        }
    });

    const vm = app.mount('#root');

5. 插件 plugin

把通用性的功能封装起来

    const myPlugin = {
        install(app, options) {
            app.provide('name', "Hello World");
        }
    }
    const app = Vue.createApp({
        template: `
        
        `
    });

    app.component('my-title', {
        inject: ['name'],
        template: `
{{name}}
` }); app.use(myPlugin, { name: 'test' }); const vm = app.mount('#root');

6. setup 函数

为了增加代码的可维护性,setup 可以将相关代码段聚集在一起。
setup 函数执行在 created 之前,即实例被完全初始化之前。

    const app = Vue.createApp({
        template: `
        
{{name}}
`, methods: { test() { console.log(this.$options.setup()); } }, mounted() { this.test(); }, setup(props, context) { return { name: 'hello', handleClick: () => { alert("click"); } } } }); const vm = app.mount('#root');

7. ref、reactive 响应式引用

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

ref 只适合处理基本类型的数据

    const app = Vue.createApp({
        template: `
        
{{name}}
`, setup(props, context) { const { ref } = Vue; // proxy , 'hello' 变成 proxy({value: 'hello'}) 这样的一个响应式引用 let name = ref('hello'); setTimeout(() => { name.value = 'world' }, 2000) return { name } } }); const vm = app.mount('#root');

reactive 处理非基础类型的数据

    const app = Vue.createApp({
        template: `
        
{{nameObj[0]}}
`, setup(props, context) { const { reactive } = Vue; const nameObj = reactive([123]); setTimeout(() => { nameObj[0] = 456; }, 2000); return { nameObj } } }); const vm = app.mount('#root');

readonly 使用

    const app = Vue.createApp({
        template: `
        
{{nameObj[0]}}
`, setup(props, context) { const { reactive, readonly } = Vue; const nameObj = reactive([123]); const copyNameObj = readonly(nameObj); setTimeout(() => { nameObj[0] = 456; copyNameObj[0] = 456; }, 2000); return { nameObj, copyNameObj } } }); const vm = app.mount('#root');

toRefs 会把 proxy({name: 'hello'}) 转换成 {name: proxy({value: 'hello'})}

    const app = Vue.createApp({
        template: `
        
{{name}}
`, setup(props, context) { const { reactive, readonly, toRefs } = Vue; const nameObj = reactive({ name: 'hello' }); setTimeout(() => { nameObj.name = "world"; }, 2000); const { name } = toRefs(nameObj); return { name } } }); const vm = app.mount('#root');

8. toRef 以及 context

toRef 将属性转换成响应式引用

    const app = Vue.createApp({
        template: `
        
name: {{name}}, age: {{age}}
`, setup(props, context) { const { reactive, toRef } = Vue; const data = reactive({ name: 'hello', age: 0 }); const name = toRef(data, 'name'); const age = toRef(data, 'age'); setTimeout(() => { age.value = "20" }, 2000); return { name, age }; } }); const vm = app.mount('#root');

contextslots

    const app = Vue.createApp({
        template: `
            parent
        `
    });

    app.component('child', {

        setup(props, context) {
            const { h } = Vue;
            const { attrs, slots, emit } = context;
            // console.log(attrs.app);  // None-Props 属性
            return () => h('div', {}, slots.default());
        }
    });

    const vm = app.mount('#root');

contextemit

    const app = Vue.createApp({
        methods: {
            handleChange() {
                alert('change');
            }
        },
        template: `
            parent
        `
    });

    app.component('child', {
        template: '
123
', setup(props, context) { const { h } = Vue; const { attrs, slots, emit } = context; function handleClick() { emit('change'); } return { handleClick }; } }); const vm = app.mount('#root');

9. 计算属性 computed

使用 composition api 配合 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;
            // });
            let countAddFive = computed({
                get: () => {
                    return count.value + 5;
                },
                set: (param) => {
                    count.value = param - 5;
                }
            });
            setTimeout(() => {
                countAddFive.value = 100;
            }, 2000);
            return {
                count,
                handleClick,
                countAddFive
            };
        },
        template: `
            
{{count}} -- {{countAddFive}}
` }); const vm = app.mount('#root');

10. 侦听器 watch 和 watchEffect

watch 具备一定的惰性,参数可以拿到当前值和之前值

    const app = Vue.createApp({
        setup() {
            const { reactive, watch, toRefs } = Vue;
            const nameObj = reactive({ name: 'hello' });
            watch(() => nameObj.name, (currentValue, preValue) => {
                console.log(currentValue, preValue);
            });
            const { name } = toRefs(nameObj);
            return { name };
        },
        template: `
            
Name:
Name is {{ name }}
` }); const vm = app.mount('#root');

一个侦听多个数据的变化

    const app = Vue.createApp({
        setup() {
            const { reactive, watch, toRefs } = Vue;
            const nameObj = reactive({ name: 'hello', englishName: 'world' });
            watch([() => nameObj.name, () => nameObj.englishName], ([curName, curEng], [preName, preEng]) => {
                console.log(curName, preName, '---', curEng, preEng);
            });
            const { name, englishName } = toRefs(nameObj);
            return { name, englishName };
        },
        template: `
            
Name:
Name is {{ name }}
English Name:
English Name is {{ englishName }}
` }); const vm = app.mount('#root');

watch 和 watchEffect 的区别:

  • watchEffect 没有惰性,立即执行,即代码一加载就执行;
  • 不需要传递要侦听的内容,自动会感知代码依赖,不需要传递很多参数,只要传递一个回调函数
  • 不能获取之前数据的值
    const app = Vue.createApp({
        setup() {
            const { reactive, watch, watchEffect, toRefs } = Vue;
            const nameObj = reactive({ name: 'hello', englishName: 'world' });
            // watch([() => nameObj.name, () => nameObj.englishName], ([curName, curEng], [preName, preEng]) => {
            //     console.log(curName, preName, '---', curEng, preEng);
            // }, { immediate: true });
            const stop = watchEffect(() => {
                console.log('nameObj.name', nameObj.name);
                setTimeout(() => {
                    stop();
                }, 5000)
            });
            const { name, englishName } = toRefs(nameObj);
            return { name, englishName };
        },
        template: `
            
Name:
Name is {{ name }}
English Name:
English Name is {{ englishName }}
` }); const vm = app.mount('#root');

11. 生命周期函数

mounted => onMounted
beforeUpdate => onBeforeUpdate

setup 执行在 beforeCreatecreated 之间,所以没有这 2 个函数对应的 composition api 生命周期函数。

onRenderTracked 渲染后收集响应式的依赖。
onRenderTriggered 每次重新渲染被触发的时候。

    const app = Vue.createApp({
        template: `
        
Hello world
`, setup() { const { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onRenderTracked, onRenderTriggered } = Vue; onBeforeMount(() => { console.log("onBeforeMount"); }); } }); const vm = app.mount('#root');

12. provide inject ref 用法

使用 readonly 处理单向数据流

    const app = Vue.createApp({
        template: `
        
`, setup() { const { provide, ref, readonly } = Vue; const name = ref("hello"); provide('name', readonly(name)); provide('changeName', (value) => { name.value = value; }); return {} } }); app.component('child', { setup() { const { inject } = Vue; const name = inject('name'); const changeName = inject('changeName'); const handleClick = () => { changeName('world'); }; return { name, handleClick }; }, template: `
{{name}}
` }); const vm = app.mount('#root');

获取真实的 DOM 元素节点

    const app = Vue.createApp({
        template: `
        
hello world
`, setup() { const { ref, onMounted } = Vue; const hello = ref(null); onMounted(() => { console.log(hello.value); }); return { hello } } }); const vm = app.mount('#root');

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据