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


Posted in Vue.js onJanuary 13, 2021

前言

本文将对vue组件如何解析以及渲染做一个讲解。

我们可以通过Vue.component注册全局组件,之后可以在模板中进行使用

<div id="app">
  <my-button></my-button>
</div>
<script>
 Vue.component("my-button", {
    template: "<button> 按钮组件</button>",
   });
let vm = new Vue({
	el:'#app'
});
</script>

全局组件解析原理

为了保证组件的隔离,每个组件通过extend方法产生一个新的类,去继承父类。并把用户通过Vue.component方法传入的 opts 合并到 vue.options.components,再vue初始化时合并Vue.options.components 和 vm.$options.components 。

1.Vue.component 方法

Vue.options._base = Vue; //可以通过\_base 找到 vue
Vue.options.components = {}; 

Vue.component = function (id, definition) {
  //每个组件产生一个新的类去继承父亲
  definition = this.options._base.extend(definition);

  console.log("1.给组件创造一个构造函数,基于Vue", definition);

  this.options.components[id] = definition;
 };

2.Vue.extend 方法

extend 方法就是产生一个继承于 Vue 的类,并且他身上应该有父类的所有功能。

import {mergeOptions} from '../util/index'
Vue.extend = function (definition) {
  const Vue = this;
  const Sub = function VueComponent(options) {
   this._init(options);
  };
  Sub.prototype = Object.create(Vue.prototype);
  Sub.prototype.constructor = Sub;
  Sub.options = mergeOptions(Vue.options, definition); 
  return Sub;
 };

3.属性合并

合并Vue.options 和 Vue.component(definition)传入的 definition

strats.components = function (parentVal, childVal) {
 let options = Object.create(parentVal);
 if (childVal) {
  for (let key in childVal) {
   options[key] = childVal[key];
  }
 }
 return options;
};

4.初始化合并

合并Vue.options.components 和 vm.$options.components

Vue.prototype._init = function (options) {
  const vm = this;
 ++ vm.$options = mergeOptions(vm.constructor.options, options); 
  //...
  initState(vm);
  if (vm.$options.el) {
   //将数据挂载到这个模版上
   vm.$mount(vm.$options.el);
  }
 };

好哒,到这里我们就实现了全局组件的解析。

下面我们再来康康组件如何渲染的吧?

组件的渲染原理

在创建虚拟节点时我们要通过isReservedTag 判断当前这个标签是否是组件,普通标签的虚拟节点和组件的虚拟节点有所不同,如果 tag 是组件 应该渲染一个组件的 vnode。

export function isReservedTag(str) {
 let reservedTag = "a,div,span,p,img,button,ul,li";
 return reservedTag.includes(str);
}

1.创建组件虚拟节点

createComponent 创建组件的虚拟节点,通过data上有无hook来区分是否为组件

export function createElement(vm, tag, data = {}, ...children) {
  // 如果tag是组件 应该渲染一个组件的vnode
  if (isReservedTag(tag)) {
    return vnode(vm, tag, data, data.key, children, undefined);
  } else {
    const Ctor = vm.$options.components[tag]
    return createComponent(vm, tag, data, data.key, children, Ctor);
  }
}
// 创建组件的虚拟节点, 为了区分组件和元素 data.hook 
function createComponent(vm, tag, data, key, children, Ctor) {
  // 组件的构造函数
  if(isObject(Ctor)){
    Ctor = vm.$options._base.extend(Ctor); // Vue.extend 
  }
  data.hook = { // 等会渲染组件时 需要调用此初始化方法
    init(vnode){
      let vm = vnode.componentInstance = new Ctor({_isComponent:true}); // new Sub 会用此选项和组件的配置进行合并
      vm.$mount(); // 组件挂载完成后 会在 vnode.componentInstance.$el 
    }
  }
  return vnode(vm,`vue-component-${tag}`,data,key,undefined,undefined,{Ctor,children})
}

2.创建组件的真实节点

typeof tag === "string",有可能是组件的虚拟节点,则调用createComponent。

export function patch(oldVnode,vnode){
  // 1.判断是更新还是要渲染
  if(!oldVnode){
    return createElm(vnode);
  }else{
    // ...
  }
}

function createElm(vnode) {
 let { tag, data, children, text, vm } = vnode;
 if (typeof tag === "string") {
  if (createComponent(vnode)) {
   //返回组件对应的真实节点
   return vnode.componentInstance.$el;
  }
  vnode.el = document.createElement(tag); // 虚拟节点会有一个el属性,对应真实节点
  children.forEach((child) => {
   vnode.el.appendChild(createElm(child));
  });
 } else {
  vnode.el = document.createTextNode(text);
 }
 return vnode.el;
}

createComponent 通过 data上是否有hook.init方法,判断是否组件虚拟节点

是的话则调用组件上 data.hook.init

创建组件实例,并赋值给vnode.componentInstance

vnode.componentInstance 有值说明对应组件的真实 dom 已经生成

function createComponent(vnode) {
  let i = vnode.data;
  if((i = i.hook) && (i = i.init)){
    i(vnode);
  }
  if(vnode.componentInstance){
    return true;
  }
}

调用init方法,创造组件的实例并该进行挂载

data.hook = {
  init(vnode){
    let child = vnode.componentInstance = new Ctor({});
    child.$mount(); // 组件的挂载
  }
}

小结

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

对组件进行 new 组件().$mount() => vm.$el

将组件的$el 插入到父容器中 (父组件)

就完成啦~

以上就是vue组件是如何解析及渲染的?的详细内容,更多关于vue 组件解析和渲染的资料请关注三水点靠木其它相关文章!

Vue.js 相关文章推荐
vue实现下载文件流完整前后端代码
Nov 17 Vue.js
在vue中动态修改css其中一个属性值操作
Dec 07 Vue.js
vue 使用 sortable 实现 el-table 拖拽排序功能
Dec 26 Vue.js
为什么推荐使用JSX开发Vue3
Dec 28 Vue.js
vue实现图书管理系统
Dec 29 Vue.js
Vue中引入svg图标的两种方式
Jan 14 Vue.js
vue 组件基础知识总结
Jan 26 Vue.js
vue项目两种方式实现竖向表格的思路分析
Apr 28 Vue.js
vue实现简单数据双向绑定
Apr 28 Vue.js
Vue如何实现组件间通信
May 15 Vue.js
vue中div禁止点击事件的实现
Apr 02 Vue.js
详解Vue3使用axios的配置教程
Apr 29 Vue.js
vue实现一个获取按键展示快捷键效果的Input组件
Jan 13 #Vue.js
vue使用vue-quill-editor富文本编辑器且将图片上传到服务器的功能
Jan 13 #Vue.js
基于VUE实现简单的学生信息管理系统
Jan 13 #Vue.js
详解为什么Vue中的v-if和v-for不建议一起用
Jan 13 #Vue.js
vue自定义组件实现双向绑定
Jan 13 #Vue.js
Vue页面渲染中key的应用实例教程
Jan 12 #Vue.js
Vue项目中使用mock.js的完整步骤
Jan 12 #Vue.js
You might like
phpmyadmin导入(import)文件限制的解决办法
2009/12/11 PHP
jQuery获取json后使用zy_tmpl生成下拉菜单
2015/03/27 PHP
深入理解PHP内核(一)
2015/11/10 PHP
PHP中类的自动加载的方法
2017/03/17 PHP
PHP实现深度优先搜索算法(DFS,Depth First Search)详解
2017/09/16 PHP
ThinkPHP防止重复提交表单的方法实例分析
2018/05/10 PHP
javascript 面向对象编程基础 多态
2009/08/21 Javascript
js 优化次数过多的循环 考虑到性能问题
2011/03/05 Javascript
Jquery中&quot;$(document).ready(function(){ })&quot;函数的使用详解
2013/12/30 Javascript
js判断游览器类型及版本号的代码
2014/05/11 Javascript
jQuery 隐藏和显示 input 默认值示例
2014/06/03 Javascript
jQuery中serializeArray()与serialize()的区别实例分析
2015/12/09 Javascript
Bootstrap企业网站实战项目4
2016/10/14 Javascript
jQuery实现元素的插入
2017/02/27 Javascript
JS实现标签页切换效果
2017/05/04 Javascript
详解angular ui-grid之过滤器设置
2017/06/07 Javascript
AngularJs用户登录问题处理(交互及验证、阻止FQ处理)
2017/10/26 Javascript
10行原生JS实现文字无缝滚动(超简单)
2018/01/02 Javascript
p5.js 毕达哥拉斯树的实现代码
2018/03/23 Javascript
浅谈vue中使用编辑器vue-quill-editor踩过的坑
2020/08/03 Javascript
在antd Table中插入可编辑的单元格实例
2020/10/28 Javascript
python正常时间和unix时间戳相互转换的方法
2015/04/23 Python
Python脚本实现Web漏洞扫描工具
2016/10/25 Python
pyqt5移动鼠标显示坐标的方法
2019/06/21 Python
利用Tensorflow构建和训练自己的CNN来做简单的验证码识别方式
2020/01/20 Python
python3光学字符识别模块tesserocr与pytesseract的使用详解
2020/02/26 Python
CSS3实现DIV圆角效果完整代码
2012/10/10 HTML / CSS
公司部门司机岗位职责
2014/01/03 职场文书
优秀管理者获奖感言
2014/02/17 职场文书
法人委托书范本
2014/04/04 职场文书
政治思想表现评语
2014/05/04 职场文书
党员三严三实心得体会
2014/10/13 职场文书
毕业实习计划书
2015/01/16 职场文书
绍兴鲁迅故居导游词
2015/02/09 职场文书
大学生社会服务心得体会
2016/01/22 职场文书
党员公开承诺书2016
2016/03/24 职场文书