Hello, 好久不见,最近遇到了很多的事情,因为春招形势很差,本来想签了一个薪资差不多的,想先积累经验等经济回暖。结果在入职前两周被毁约了,现在只能破罐子破摔,大概率要run去社招了。
最近在复习Vue的源码,今天带大家手写实现一下Vue内置组件component,比较简单,最近面试有被问到。

PS: 哪位大佬公司还缺前端,能帮忙内推的,可以加下我联系方式,22届应届生,有6个月实习经验,一线城市均可。

前言

​Vue​​​大家都很熟悉,除了原生的组件,其自己也封装了一下内置组件,比如​​component​​​,​​transition​​​,​​keep-alive​​等等。

​component​​​算是用的比较多的了,当我们遇到需要根据不同条件显示不同组件的时候,一般都是用​​component​​​来实现。当然你也可以​​v-if,v-else-if,v-else​​,就显的比较笨了。

大家如果没用过,可以先自己尝试一下这个​​component​​​组件。最主要的就是它有一个​​is​​属性,你给is赋予什么组件名,它就渲染什么组件。

内置组件component的使用

我写一个小​​demo​​演示一下。

先随意的写三个组件,​​A​​​,​​B​​​,​​C​​。

手写实现Vue内置组件component(Vue进阶)_vue.js


组件内容就是​​aaaa​​​,​​bbbb​​​,​​cccc​​,方便我们辨认当然渲染的是哪个组件。

手写实现Vue内置组件component(Vue进阶)_javascript_02


然后集体引入,挂载。

手写实现Vue内置组件component(Vue进阶)_javascript_03


手写实现Vue内置组件component(Vue进阶)_前端_04


视图内容大概这样写,需求就是,准备三个按钮,点击哪个按钮就显示哪个组件。

<div>
<button @click="changeComp('A')">显示A</button>
<button @click="changeComp('B')">显示B</button>
<button @click="changeComp('C')">显示C</button>
</div>
<component :is="compList"></component>

​compList​​​提前声明好,默认是​​A​​组件。

data() {
return {
compList: 'A'
};
},

​changeComp​​函数内容如下:

methods: {
changeComp(comp) {
this.compList = comp;
},
}

OK,这就完事了,大家可以自己试一下,是可以完成既定的需求的。

手写实现Vue内置组件component(Vue进阶)_vue.js_05

component组件的原理分析

我们今天的任务是,了解内置组件​​component​​的原理,并手写实现一个。

那么​​component​​​的实现原理是怎么样的呢,这个就需要牵扯一块比较大的知识链了,也是​​Vue​​​的核心内容。关于​​Vue​​​的​​虚拟DOM​​以及模板编译的部分内容。

简单来说,​​Vue​​​内部实现了一个​​虚拟DOM​​​来妥善解决​​原生DOM​​的性能问题。

虚拟DOM与原生DOM

比如我们当前需要插入​​1000​​​个​​DOM​​​节点,如果是​​原生DOM​​​来做的话,就是扎扎实实的,一个个操作,改变​​DOM​​​,​​DOM​​​需要被改变​​1000​​次,这对于性能是极大的损耗,造成很多的问题。

​虚拟DOM​​​的原理就是,先在框架内部用对象模拟一下​​原生DOM​​​的形态,记录你这​​1000​​​次的​​DOM​​​操作,最后将​​DOM​​​被操作​​1000​​​次后的形态赋给​​原生DOM​​​。这样就能极大的优化大量​​DOM​​操作带来的负面影响。

然后再来思考一下,我们平时写的​​.vue​​​文件,其实跟原生写法是有区别的,无论是​​HTML​​​、​​JS​​​还是​​CSS​​​,在编写阶段有做了些许的改动,这样做有助于提高我们的编写效率。但是浏览器是只认原生的​​HTML​​​、​​CSS​​​和​​JS​​​的,所以我们编写的组件内容,其实只是一个​​template​​​模板,需要进行编译转换为原生的​​DOM​​才能渲染到浏览器上。

而​​componet​​​组件其实就是内部做了这个事情,将你传入的组件, 先转换为​​虚拟DOM​​​,然后渲染为真实​​DOM​​,展示到视图上。

render函数的使用

这里面就涉及到一个知识点了,关于​​render​​​函数的使用,具体的内容大家可以去​​Vue​​​文档详细了解一下​​render​​函数。可能大家日常开发用的比较少,涉及一些偏底层的东西时才会遇到。

我这里只介绍​​render​​​函数做的事情。
它的形态大概是这个样式。

render(h) {
// return h('A');
return h('div', '6666');
},

​render​​​函数接收一个参数,比如叫它​​h​​​,​​h​​​也是一个函数,它的作用就是将传入的内容构建为​​虚拟DOM​​​,这个传入的内容支持原生的写法,也支持​​Vue​​组件。

比如我代码里给出的,​​h('div', '6666')​​​,​​h​​​函数就会生成一个​​div​​​组件,文本内容是​​666​​​。被注释掉的,就是传入​​Vue​​​中自己的写的组件名字为​​A​​,同样支持。

但是​​h​​​函数仅仅只是将传入的内容,生成​​虚拟DOM​​​,不是真实的​​原生DOM​​​,然后将它​​return​​​出去,​​render​​​函数才会将这个​​虚拟DOM​​​渲染成为​​真实DOM​​。

上述关于​​render​​​函数的内容不知道大家是否理解,可以去​​Vue​​​官方文档里,详细看一下,然后自己写写​​demo​​​体验一下,​​render​​​函数算是​​Vue​​进阶中比较重要的内容了。

所以,话说回来,知道了​​render​​​函数这个东西,我们就能够比较好的实现​​component​​​这个内置组件了。​​component​​​组件会接收一个属性​​is​​​,​​is​​​的值就是我们要渲染的组件。​​component​​​组件的内容其实就是进行了 ​​Vue组件 => 虚拟DOM => 真实DOM​​​,渲染视图,其实就通过​​render​​函数实现就可以。

尝试手写实现component

话不多说,我们试一下。

因为组件内容比较少,所以我们直接使用​​Vue.component​​来编写组件内容。

Vue.component("myComponent", {
props: ["is"],
render(h) {
return h(this.is);
},
});

其实核心代码就上面这几行,组件名字是​​myComponent​​​,​​props​​​的作用就是指定组件要接收的参数​​is​​​。然后编写一下​​render​​​函数,因为是渲染​​Vue​​​组件,所以直接​​return h(this.is)​​就可以。

将这段代码写在​​JS​​​里,然后就可以使用了。记得要​​import Vue from 'vue'​​​来引入​​Vue​​​,因为我们是通过​​Vue.component​​来编写组件的。

下面我们试一试,这个​​myComponent​​是否有用。

<div>
<button @click="changeComp('A')">显示A</button>
<button @click="changeComp('B')">显示B</button>
<button @click="changeComp('C')">显示C</button>
</div>
<component :is="compList"></component>
<my-component :is="compList"></my-component>

手写实现Vue内置组件component(Vue进阶)_dom操作_06


实际操作后可以发现,我们自己写的​​myComponent​​​和​​Vue​​​内置的​​component​​效果是一模一样的,大家自己也可以试一下。

完整代码:

<template>
<div>
<div>
<button @click="changeComp('A')">显示A</button>
<button @click="changeComp('B')">显示B</button>
<button @click="changeComp('C')">显示C</button>
</div>
<component :is="compList"></component>
<my-component :is="compList"></my-component>
</div>
</template>

<script>
import Vue from "vue";
import A from "../components/A.vue";
import B from "../components/B.vue";
import C from "../components/C.vue";

Vue.component("myComponent", {
props: ["is"],
render(h) {
return h(this.is);
},
});
export default {
components: {
A,
B,
C,
},
data() {
return {
compList: 'A'
};
},
methods: {
changeComp(comp) {
this.compList = comp;
},
},
};
</script>

<style scoped>

</style>

总结

今天的内容是带着大家手写实现​​Vue​​​的内置组件​​component​​​,在尝试实现某一个东西的时候,就需要先思考它的作用以及内部原理。手写​​component​​​的过程比较简单,但是涉及到了很多​​Vue​​的原理性知识点,比如虚拟DOM、render函数、模板编译等。


公众号: Code程序人生