• 售前

  • 售后

热门帖子
入门百科

vue组件是如何解析及渲染的?

[复制链接]
123457389 显示全部楼层 发表于 2021-10-25 19:48:14 |阅读模式 打印 上一主题 下一主题
媒介


本文将对vue组件怎样分析以及渲染做一个讲授。
  1. 我们可以通过Vue.component注册全局组件,之后可以在模板中进行使用
复制代码
  1. <div id="app">
  2.   <my-button></my-button>
  3. </div>
  4. <script>
  5. Vue.component("my-button", {
  6.     template: "<button> 按钮组件</button>",
  7.    });
  8. let vm = new Vue({
  9.         el:'#app'
  10. });
  11. </script>
复制代码
全局组件分析原理


为了包管组件的隔离,每个组件通过extend方法产生一个新的类,去继承父类。并把用户通过Vue.component方法传入的 opts 归并到 vue.options.components,再vue初始化时归并Vue.options.components 和 vm.$options.components 。
1.Vue.component 方法
  1. Vue.options._base = Vue; //可以通过\_base 找到 vue
  2. Vue.options.components = {};
  3. Vue.component = function (id, definition) {
  4.   //每个组件产生一个新的类去继承父亲
  5.   definition = this.options._base.extend(definition);
  6.   console.log("1.给组件创造一个构造函数,基于Vue", definition);
  7.   this.options.components[id] = definition;
  8. };
复制代码
2.Vue.extend 方法


extend 方法就是产生一个继承于 Vue 的类,并且他身上应该有父类的全部功能。
  1. import {mergeOptions} from '../util/index'
  2. Vue.extend = function (definition) {
  3.   const Vue = this;
  4.   const Sub = function VueComponent(options) {
  5.    this._init(options);
  6.   };
  7.   Sub.prototype = Object.create(Vue.prototype);
  8.   Sub.prototype.constructor = Sub;
  9.   Sub.options = mergeOptions(Vue.options, definition);
  10.   return Sub;
  11. };
复制代码
3.属性归并


归并Vue.options 和 Vue.component(definition)传入的 definition
  1. strats.components = function (parentVal, childVal) {
  2. let options = Object.create(parentVal);
  3. if (childVal) {
  4.   for (let key in childVal) {
  5.    options[key] = childVal[key];
  6.   }
  7. }
  8. return options;
  9. };
复制代码
4.初始化归并


归并Vue.options.components 和 vm.$options.components
  1. Vue.prototype._init = function (options) {
  2.   const vm = this;
  3. ++ vm.$options = mergeOptions(vm.constructor.options, options);
  4.   //...
  5.   initState(vm);
  6.   if (vm.$options.el) {
  7.    //将数据挂载到这个模版上
  8.    vm.$mount(vm.$options.el);
  9.   }
  10. };
复制代码
好哒,到这里我们就实现了全局组件的分析。
下面我们再来康康组件怎样渲染的吧?
组件的渲染原理


在创建虚拟节点时我们要通过isReservedTag 判断当前这个标签是否是组件,普通标签的虚拟节点和组件的虚拟节点有所差异,如果 tag 是组件 应该渲染一个组件的 vnode。
  1. export function isReservedTag(str) {
  2. let reservedTag = "a,div,span,p,img,button,ul,li";
  3. return reservedTag.includes(str);
  4. }
复制代码
1.创建组件虚拟节点


createComponent 创建组件的虚拟节点,通过data上有无hook来区分是否为组件
  1. export function createElement(vm, tag, data = {}, ...children) {
  2.   // 如果tag是组件 应该渲染一个组件的vnode
  3.   if (isReservedTag(tag)) {
  4.     return vnode(vm, tag, data, data.key, children, undefined);
  5.   } else {
  6.     const Ctor = vm.$options.components[tag]
  7.     return createComponent(vm, tag, data, data.key, children, Ctor);
  8.   }
  9. }
  10. // 创建组件的虚拟节点, 为了区分组件和元素 data.hook
  11. function createComponent(vm, tag, data, key, children, Ctor) {
  12.   // 组件的构造函数
  13.   if(isObject(Ctor)){
  14.     Ctor = vm.$options._base.extend(Ctor); // Vue.extend
  15.   }
  16.   data.hook = { // 等会渲染组件时 需要调用此初始化方法
  17.     init(vnode){
  18.       let vm = vnode.componentInstance = new Ctor({_isComponent:true}); // new Sub 会用此选项和组件的配置进行合并
  19.       vm.$mount(); // 组件挂载完成后 会在 vnode.componentInstance.$el
  20.     }
  21.   }
  22.   return vnode(vm,`vue-component-${tag}`,data,key,undefined,undefined,{Ctor,children})
  23. }
复制代码
2.创建组件的真实节点


typeof tag === "string",有大概是组件的虚拟节点,则调用createComponent。
  1. export function patch(oldVnode,vnode){
  2.   // 1.判断是更新还是要渲染
  3.   if(!oldVnode){
  4.     return createElm(vnode);
  5.   }else{
  6.     // ...
  7.   }
  8. }
  9. function createElm(vnode) {
  10. let { tag, data, children, text, vm } = vnode;
  11. if (typeof tag === "string") {
  12.   if (createComponent(vnode)) {
  13.    //返回组件对应的真实节点
  14.    return vnode.componentInstance.$el;
  15.   }
  16.   vnode.el = document.createElement(tag); // 虚拟节点会有一个el属性,对应真实节点
  17.   children.forEach((child) => {
  18.    vnode.el.appendChild(createElm(child));
  19.   });
  20. } else {
  21.   vnode.el = document.createTextNode(text);
  22. }
  23. return vnode.el;
  24. }
复制代码
createComponent 通过 data上是否有hook.init方法,判断是否组件虚拟节点
是的话则调用组件上 data.hook.init
创建组件实例,并赋值给vnode.componentInstance
vnode.componentInstance 有值阐明对应组件的真实 dom 已经天生
  1. function createComponent(vnode) {
  2.   let i = vnode.data;
  3.   if((i = i.hook) && (i = i.init)){
  4.     i(vnode);
  5.   }
  6.   if(vnode.componentInstance){
  7.     return true;
  8.   }
  9. }
复制代码
调用init方法,创造组件的实例并该举行挂载
  1. data.hook = {
  2.   init(vnode){
  3.     let child = vnode.componentInstance = new Ctor({});
  4.     child.$mount(); // 组件的挂载
  5.   }
  6. }
复制代码
小结


对组件举行 new 组件().$mount() => vm.$el
将组件的$el 插入到父容器中 (父组件)
就完成啦~
以上就是vue组件是怎样分析及渲染的?的详细内容,更多关于vue 组件分析和渲染的资料请关注草根技术分享其它干系文章!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作