Vue 组件创建的流程源码分析

创建组件的时候都会调用 Vue.extend

注册组件第二个参数默认会调用extend,Vue.extend 使用Vue基础构造器 产生子类
Vue.extend() 中data必须是一个函数,继承与Vue,可以new和挂载
Vue.component("",Vue.extend({})) //传入的是对象

  • 子类可以继承父类 init
  • 每个组件都有自己的数据,希望每个组件都是独立的所以希望new创造一个实例

为啥data必须是函数,而不是对象

class Component{
    constructor(){
        this.data = obj;
    }
}
new Component().data
new Component().data

这样复用了同一个对象所以改写为,这样new的时候可以拿到全新的对象

let fn = function(){
    return {
    }
}
class Component{
    constructor(){
        this.data = fn;
    }
}

重写Sub.prototype.constructor 指向(源码中有写)

  • Sub.prototype = Object.create(Super.prototype);
  • Object.setPrototypeOf()
  • Object.create 原理
function create(parentProtptype){
    const Fn = function(){}
    Fn.prototype = parentProtptype
    return new Fn;
}
Sun.prototype = Object.create(Super.prototype);//继承原型方法
Sub.prototype.constructor = Sub;//Object.create 会产生一个新的实例作为子类的原型,此时constructor会指向错误

因为new Fn的constructor指向的是Parent,所以Sub.prototype需要重写

———————————————— 分割线 ————————————————————

组件初始化流程

1:调用initGlobalAPI里边有2个重要的方法

  • Vue.extend:产生Vue的子类(实例),其中mergeOptions合并了全局属性和子组件的属性到,组件实例的options上
  • Vue.component:将产生的组件是放到 Vue.options.components[组件名称]全局上
export function initGlobalAPI(Vue) {
    Vue.options = {};//全局属性 每个组件初始化的时候 将这些属性放到每个组件桑

    Vue.mixin = function(options){
        this.options = mergeOptions(this.options,options);
        console.log(this.options);
        return this;
    }
    //vue.component -> Vue.extend
    Vue.options._base = Vue;
    //等会我通知Vue.extend方法可以产生一个子类 new子类的时候会执行代码初始化流程(组件的初始化)
    Vue.extend = function (opt) {//会产生一个子类
        const Super = this;
        const Sub = function (options) {//创造一个组件 其实就是new这个组件的类(组件的初始化)
            this._init(options)
        }
        Sub.prototype = Object.create(Super.prototype);//继承原型方法
        Sub.prototype.constructor = Sub;//Object.create 会产生一个新的实例作为子类的原型,此时constructior会指向错误 constructor就这个问题
        
        //父类的属性要和子类的属性进行合并
        Sub.options = mergeOptions(Super.options,opt);//需要让子类 能拿到我们Vue定义的全局组件
        //Sub.mixin = Vue.mixin; nextTixk等等
        return Sub;//产生Vue的子类
    }
    Vue.options.components = {};//存放全局组件的
    Vue.component = function name(id, definition) {//definition 可以传入对象或者函数
        let name = definition.name || id;
        definition.name = name;
        if(isObject(definition)){
            definition = Vue.extend(definition);
        }
        Vue.options.components[name] = definition;//缓存组件到全局上(维护关系)
        console.log(Vue.options.components);
    }

}

在renderMixin的时候会调用

 Vue.prototype._c = function () { // createElement 创建元素型的节点
        const vm = this;
        return createElement(vm, ...arguments)
    }

所以在createElement,需要对组件进行处理(要区分组件和普通元素去创建虚拟节点)

function createComponent(vm,tag,data,children,key,Ctor) {
  if(isObject(Ctor)){//组件的定义一定是通过Vue.extend进行包裹的
    Ctor = vm.$options_base.extend(Ctor)
  }
  //组件的hook 源码里是进行遍历挂载hook
  data.hook = {
    //组件的生命周期
    init(){
    },
    //组件的更新流程
    prepatch(){
    },
   //......
  }
  //每个组件 默认的名字内部都会给你拼接一下 vue-component-1-my-button(数组是一个序号 每new一个+1)
  let componentOptions = vnode(vm,tag,data,undefined,key,undefined,{Ctor,children,tag,propsData,listeners});
  return componentOptions;//componentOptions(非常重要包含了Ctor children等) 存放了一个重要的属性Ctor
}
//tag 有可能是组件 createElement({}) createElement(function(){})
export function createElement(vm, tag, data = {}, ...children) { // 返回虚拟节点 _c('',{}....)

   //这个时候是虚拟节点 还没有nodeType; 这里不考虑复杂的就是string类型 看看是不是普通标签 
  if (!isReservedTag(tag)) {
    //Ctor 是组件最重要的属性
    let Ctor = vm.$options.components[tag]; // 组件的初始化 就是new 组件的构造函数 tag标签
    //创建组件的虚拟节点  如果是组件要拿到组件的定义
    return createComponent(vm, tag, data, children, data.key, Ctor);
  }

  return vnode(vm, tag, data, children, data.key, undefined)
}

export function createText(vm, text) { // 返回虚拟节点
  return vnode(vm, undefined, undefined, undefined, undefined, text)
}

//options 可能是对象(自己定义的组件) 所以不放Ctor
function vnode(vm,tag,data,children,key,text,options) {
  return {
    vm, tag, data, children,key,text,componentOptions:options
  }
}

判断是不是原始的标签 还是组件的方法

function makeMap(str) {
  let tagList = str.split(',');
  return function (tagName) {
    return tagList.includes(tagName)
  }
}

//这里的源码在platform/web/util/element.js
export const isReservedTag = makeMap(
  'html,body,base,head,link,meta,style,title,' +
  'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
  'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +
  'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
  's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
  'embed,object,param,source,canvas,script,noscript,del,ins,' +
  'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
  'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
  'output,progress,select,textarea,' +
  'details,dialog,menu,menuitem,summary,' +
  'content,element,shadow,template,blockquote,iframe,tfoot'
)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容