文章目录
- 前言
 - 一、Mixin(混入数据)
 
- 1.1、局部Mixin认识与基本使用
 - 1.2、全局Mixin定义(app.mixin({}))
 - 1.3、Mixmin自定义属性优先级(this.$options获取自定义属性)
 - 1.4、修改Mixin中属性的优先级(使用配置方法来修改策略)
 
- 二、自定义指令(directive)
 
- 引言
 - 2.1、局部与全局自定义指令
 - 2.2、自定义指令中生命周期函数的两个参数(el、binding)
 - 2.3、简化自定义指令方式
 
- 三、teleport标签(传送门功能,``)
 - 四、render()函数(template属性底层转换)
 
- 4.1、认识render()函数(初使用)
 - 4.2、使用render()函数解决冗余问题
 - 4.3、render函数返回值h函数嵌套使用
 
前言
本篇博客是在学习技术胖-Vue3.x从零开始学-第一季 基础语法篇过程中记录整理的笔记,若文章中出现相关问题,请指出!
- 当前该链接失效了,有需要的小伙伴可以去b站或者技术胖官网去找相应的视频与笔记。
 
所有博客文件目录索引:博客目录索引(持续更新)
一、Mixin(混入数据)
1.1、局部Mixin认识与基本使用
Mixin你可以当做是一个vue实例对象,其中也可包含属性、方法、生命周期函数,在外部直接定义就是局部Mixin,你可以将局部Mixmin引入到vue实例中来进行使用其中的属性内容!
局部Mixin引入规则:
- data对象属性值优先级小于原本data对象属性值。(原本的没有同名时才会生效)
 - methods方法优先级小于原本methods属性值。(原本的没有同名时才生效)
 - 生命周期与原本的生命周期都会执行,Mixin的会优先执行,原本的会后执行!
 
示例:
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@3.1.5/dist/vue.global.js"></script>
    <script>
        // 重点1:局部mixin声明
        const mymixin = {
            data() {
                return {
                    // 1、data数据
                    num: 2
                }
            },
            methods: {
                // 2、方法
                bindclick() {
                    console.log("mixin click")
                }
            },
            // 3、生命周期函数
            created() {
                console.log("mixin created!")
            },
        }
        Vue.createApp({
            created() {
                console.log("created!")
            },
            data() {
                return {
                    num: 1
                }
            },
            // 重点2:引入局部mixin
            mixins: [mymixin],
            methods: {
                bindclick() {
                    console.log("click")
                }
            },
            template: `
                <div>{{num}}</div>
                <button @click="bindclick">点我一下</button>
            `
        }).mount("#app");
    </script>
</body>
- num属性值、methods方法执行以及生命周期函数执行示例如上图。
 
1.2、全局Mixin定义(app.mixin({}))
全局Mixmin就是使用vue实例调用mixin来进行定义:不需要像上面的使用mixins属性来引入
const app = Vue.createApp({xxx});
// 全局Mixin定义
app.mixin({
    data() {
        return {
            // 1、data数据
            num: 2
        }
    },
    methods: {
        // 2、方法
        bindclick() {
            console.log("mixin click")
        }
    },
    // 3、生命周期函数
    created() {
        console.log("mixin created!")
    },
});对应的引入规则与局部的相同!
1.3、Mixmin自定义属性优先级(this.$options获取自定义属性)
核心要点:对于自定义属性,组件中的属性优先级高于mixin属性的优先级。
- 对于获取自定义属性,你需要使用
this.$options.自定义属性名来获取。 
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@3.1.5/dist/vue.global.js"></script>
    <script>
        // 声明局部mixin
        const mymixin = {
            num: 2
        }
        const app = Vue.createApp({
            num: 1,
            // 引入局部mixin
            mixins: [mymixin],
            // 访问mixmin(原本组件中的优先级要高于mixin属性)
            template: `
                <div>{{this.$options.num}}</div>
            `
        });
        const vm = app.mount("#app");
    </script>
</body>
1.4、修改Mixin中属性的优先级(使用配置方法来修改策略)
原本是组件中的自定义属性优先级高于mixin中自定义属性的,我们可以通过app.config.optionMergeStrategies.xxx来指定返回优先级更高的属性:
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@3.1.5/dist/vue.global.js"></script>
    <script>
        const mymixin = {
            num: 2
        }
        const app = Vue.createApp({
            num: 1,
            mixins: [mymixin],
            template: `
                <div>{{this.$options.num}}</div>
            `
        });
        // 针对于自定义属性(修改策略,返回的是Mixmin中的属性在左边表示其优先级更高)
        app.config.optionMergeStrategies.num = (mixinVal, appValue) => {
            return mixinVal || appValue;//mixin中的属性在前优先级更高
        }
        const vm = app.mount("#app");
    </script>
</body>
该函数声明过后,我们浏览器来查看一下:仅有我们刚才自只能自定义的函数,可以设想一下内部可能会在执行前来进行调用得到值。

二、自定义指令(directive)
引言
若是我们想在加载组件后就光标选中该元素,我们能够相当的就是直接写一个生命周期函数,之后来调用dom元素执行focus方法:
<div id="app"></div>
<script src="https://unpkg.com/vue@3.1.5/dist/vue.global.js"></script>
<script>
    const app = Vue.createApp({
        // 利用生命周期函数:在加载过程中自动选中
        mounted() {
            this.$refs.input.focus();
        },
        template: `
<input ref="input" type="text"></input>
`
    });
    const vm = app.mount("#app");
</script>弊端:若是我们有多个dom元素都要在加载之后执行相应的操作,那么按照原本的思路就都需要写在mounted()函数中!!!可能会造成代码冗余的问题。
2.1、局部与全局自定义指令
自定义指令有什么用?
- 核心就是自定义指令能够绑定到指定的元素并且能够在自定义指令中编写对应的生命周期函数,此时就可以独立起来。
 
全局自定义指令
<div id="app"></div>
<script src="https://unpkg.com/vue@3.1.5/dist/vue.global.js"></script>
<script>
    //2、使用自定义指令v-focus
    const app = Vue.createApp({
        template: `
            <input v-focus type="text"/>
        `
    });
    // 1、定义全局组件,名称为focus,使用时v-focus
    app.directive('focus', {
        //编写生命周期函数,el参数为使用的指定元素
        mounted(el) {
            el.focus();//令其光标选中
        }
    })
    const vm = app.mount("#app");
</script>全局自定义指令
<script>
    // 1、自定义局部指令
    const mydirective = {
        // 指令名称为focus
        focus: {
            mounted(el) {
                console.log(el)
                el.focus();
            }
        }
    }
    //2、使用自定义指令v-focus
    const app = Vue.createApp({
        directives: mydirective,
        template: `
<input v-focus type="text"/>
`
    });
    const vm = app.mount("#app");
</script>上面两个例子都是引言案例的自定义指令实现方法!
2.2、自定义指令中生命周期函数的两个参数(el、binding)
使用方式:在自定义指令中的生命周期函数中写两个参数即可获取。
- el:使用自定义指令的dom元素。
 - binding:一个对象,可以拿到如
v-自定义指令:top="xxx",binding.arg拿到top,binding.value拿到xxx,并且该xxx可以使用data对象中的属性值进行动态绑定。 
示例如下:
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@3.1.5/dist/vue.global.js"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    num: 50
                }
            },
            //2、使用自定义指令v-focus
            template: `
                <input v-focus:top="num" type="text"/>
            `
        });
        // 1、定义局部指令
        app.directive('focus', {
            // 挂载之后生效
            mounted(el, bindling) {
                console.log(el, bindling);
                // v-focus:top="num" => bindling.arg拿到top  bindling.value拿到data对象中的50
                el.style[bindling.arg] = bindling.value + "px";
            },
            // 更新前:若是想要更改num值来让dom元素生效,需要在模板渲染后来执行
            beforeUpdate(el, bindling) {
                el.style[bindling.arg] = (bindling.value) + "px";
            },
        })
        const vm = app.mount("#app");
    </script>
</body>

注意:若是你想要借助自定义指令来动态修改dom元素的样式等,你需要将该操作写于beforeUpdate()中,否则无效。
2.3、简化自定义指令方式
简化方式如下:第二个参数写箭头函数,默认指的就是beforeUpdate生命周期函数
app.directive('focus', (el, bindling) => {
    el.style[bindling.arg] = bindling.value + "px";
})
三、teleport标签(传送门功能,) 
teleport标签:能够将原本组件中的元素传输到其他dom元素中,并依旧可以使用组件中的data对象数据。
写法:<teleport to="#id"></teleport>,其中to=xxx,可以填id名、class名以及标签,如#id1、.mbody、body都是可以的!!!
示例:点击按钮,将组件中的蒙层div元素挂载到页面的body标签中,实现全页面覆盖!
<style>
    .box {
        width: 300px;
        height: 500px;
        background-color: black;
        position: absolute;
        top: 50%;
        left: 50%;
        margin-top: -250px;
        margin-left: -150px;
    }
    .layerbox {
        position: absolute;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        background-color: blue;
        opacity: .5;
    }
    .layerbox div {
        width: 50px;
        height: 50px;
        background-color: yellow;
        vertical-align: middle;
        color: white;
        font-size: 50rpx;
    }
</style>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@3.1.5/dist/vue.global.js"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    showLayer: false,
                    message: "changlu"
                }
            },
            methods: {
                handleClick() {
                    this.showLayer = this.showLayer ? false : true;
                }
            },
            //2、使用自定义指令v-focus
            template: `
                <div class="box" @click="handleClick">
                    <button >点我上蒙层</button>
                    <teleport to="body">
                        <div class="layerbox" v-show="showLayer" @click="handleClick">{{message}}</div>
                    </teleport>
                </div>
            `
        });
        const vm = app.mount("#app");
    </script>
</body>
看一下浏览器中的dom结构:可以很明显的看到被移动到指定的dom元素下。

四、render()函数(template属性底层转换)
4.1、认识render()函数(初使用)
介绍描述
render()函数作用:与template属性的效果一致,都是用来生成dom元素的。
- 知识点补充(template变为虚拟dom流程):
template ->render ->h ->虚拟dom元素(如{tagname:div,text: “hello”},就是一个js对象用来描述dom元素)。最终通过虚拟dom元素转位实际dom元素进行挂载操作,中间是有这一流程的。template在底层编译之后会生成rander函数! - 目的:了解如何通过render()生成dom元素以及实际应用。
 
注意:一旦使用了render()函数,该组件中的template属性就不生效了!!!
好处:①让vue性能更快。②vue具备跨平台能力
示例
不仅仅可以使用在全局组件上,还可以使用至局部组件中:
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@3.1.5/dist/vue.global.js"></script>
    <script>
        const app = Vue.createApp({
            // 1、设置render()函数:template=>render,只不过我们这里使用reder()函数来代替template
            render() {
                console.log("Vue=>", Vue);
                const { h } = Vue;//通过解构赋值拿到h函数
                // 2、第一个参数为标签名,第二个参数为标签的属性,第三个参数为标签的内容值
                return h('h' + 1, { 'data-user': 'changlu' }, "hello,changlu!");
            },
        });
        const vm = app.mount("#app");
    </script>
</body>

4.2、使用render()函数解决冗余问题
需求:当我们在使用子组件时,若是出现子组件中使用同一类型的标签如h1、h2、h3,并且根据传递来的参数选择指定的标签展示,此时的话,我们使用普通的判断写法就会出现下面冗余问题!!!
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@3.1.5/dist/vue.global.js"></script>
    <script>
        const app = Vue.createApp({
            //2、使用自定义指令v-focus
            template: `
                <cl-item :level="2">
                    hello,changlu
                </cl-item>
            `
        });
        app.component('cl-item', {
            props: ['level'],
            template: `
                <h1 v-if="level === 1">
                    <slot/>
                </h1>
                <h2 v-if="level === 2">
                    <slot/>    
                </h2>
                <h3 v-if="level === 3">
                    <slot/>    
                </h3>
                <h4 v-if="level === 4">
                    <slot/>    
                </h4>
            `
        })
        const vm = app.mount("#app");
    </script>
</body>优化:此时我们可以借助render()函数来动态创建虚拟dom元素,最终挂载至指定dom元素上。
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@3.1.5/dist/vue.global.js"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    // 动态拿取level值
                    level: 2
                }
            },
            template: `
                <cl-item :level="level">
                    hello,changlu    
                </cl-item>
            `
        });
        app.component('cl-item', {
            props: ['level'],
            // 1、编写render()函数
            render() {
                const { h } = Vue;
                // this.$slots.default():拿到默认的插槽值,也就是hello,changlu
                // 2、返回Vue实例中的h元素,包含了虚拟dom的相关属性如标签名、属性键值对以及内部值
                return h('h' + this.level, {}, this.$slots.default());
            },
        })
        const vm = app.mount("#app");
    </script>
</body>
4.3、render函数返回值h函数嵌套使用
对于h函数之前讲不是有三个参数嘛,其中第三个参数我们还可以在嵌套返回另一个标签值,从而达到了添加多个标签的方式!!!
- 返回数组(包含多个h函数):实现插入多个标签。
 - h函数第三个参数设置h函数:实现标签内部嵌套。
 
示例:
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@3.1.5/dist/vue.global.js"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    // 动态拿取level值
                    level: 2
                }
            },
            template: `
                <cl-item :level="level">
                    hello,changlu    
                </cl-item>
            `
        });
        app.component('cl-item', {
            props: ['level'],
            render() {
                const { h } = Vue;
                // 返回数组就能够实现插入多个元素。并且你可以在h函数的第三个参数中使用h函数来表示指定的标签
                return [h('h' + this.level, {}, this.$slots.default()), h('h' + this.level, {}, h('button', {}, '按钮'))];
            },
        })
        const vm = app.mount("#app");
    </script>
</body>
我是长路,感谢你的耐心阅读。如有问题请指出,我会积极采纳!
 欢迎关注我的公众号【长路Java】,分享Java学习文章及相关资料
 Q群:851968786 我们可以一起探讨学习
 注明:转载可,需要附带上文章链接










