当前位置:首页 > 编程教程 > vue技术文章 > Vue源码解读之Component组件注册的实现

关于Vue Component组件注册

  • 发布时间:
  • 作者:码农之家
  • 点击:84

这篇文章主要知识点是关于Vue、Component、的内容,如果大家想对相关知识点有系统深入的学习,可以参阅以下电子书

Vue企业开发实战
  • 类型:Vue.js实战大小:109.6 MB格式:PDF作者:肖睿
立即下载

Tags:Vue Component 

Vue源码解读之Component组件注册的实现

什么是组件?

组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用 is 特性进行了扩展的原生 HTML 元素。

所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。

Vue可以有全局注册和局部注册两种方式来注册组件。

全局注册

注册方式

全局注册有以下两种注册方式:

通过Vue.component 直接注册。

Vue.component('button-counter', {
    //data选项必须是一个函数
    data: function () {
      return {
        count: 0
      }
    },
    template:'#clickBtn'
  })

通过Vue.extend来注册。

 var buttonComponent = Vue.extend({
    name:'button-counter',
    data: function () {
      return {
        count: 0
      }
    },
    template:'#clickBtn'
  });
 Vue.component('button-counter', buttonComponent);

具体过程

Vue初始化时,initGlobalAPI通过调用initAssetRegisters()进行组件注册。

function initAssetRegisters (Vue) {
 // 创建组件注册的方法
 // ASSET_TYPES在Vue内部定义,var ASSET_TYPES = ['component','directive','filter'];
 ASSET_TYPES.forEach(function (type) {
  Vue[type] = function (
   id,
   definition
  ) {
   //这里的definition指的是定义(Function或Object),是函数或者对象
   //如果definition不存在,直接返回options内type和id对应的
   //这里的options是指全局的组件,指令和过滤器,见图一
   if (!definition) {
    return this.options[type + 's'][id]
   } else {
    /* istanbul ignore if */
    if ("development" !== 'production' && type === 'component') {
     validateComponentName(id);
    }
    // 如果是component(组件)方法,并且definition是对象
    if (type === 'component' && isPlainObject(definition)) {
     definition.name = definition.name || id;
     //通过this.options._base.extend方法(也就是Vue.extend方法)将定义对象转化为构造器。
     //Vue.options._base = Vue;
     definition = this.options._base.extend(definition);
    }
    if (type === 'directive' && typeof definition === 'function') {
     definition = { bind: definition, update: definition };
    }
    // 将构造器赋值给 this.options[‘component'+ 's'][id]
    //全局的组件,指令和过滤器,统一挂在vue.options上。在init的时候利用mergeOptions合并策略侵入实例,供实例使用。
    this.options[type + 's'][id] = definition;
    return definition
   }
  };
 });
}

图一:

Vue源码解读之Component组件注册的实现

initAssetRegisters里面通过this.options._base.extend方法将定义对象转化为构造器,而options._base.extend其实就是Vue.extend。接下来我们就看一下Vue.extend做了什么。

Vue.extend = function (extendOptions) {
  extendOptions = extendOptions || {};
  var Super = this;
  var SuperId = Super.cid;
  //组件缓存
  var cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {});
  //如果组件已经被缓存在extendOptions上则直接取出
  if (cachedCtors[SuperId]) {
   return cachedCtors[SuperId]
  }

  //如果有name属性,检验name拼写是否合法
  var name = extendOptions.name || Super.options.name;
  if ("development" !== 'production' && name) {
   validateComponentName(name);
  }

  var Sub = function VueComponent (options) {
   this._init(options);
  };
  //将vue上原型的方法挂在Sub.prototype中,Sub的实例同时也继承了vue.prototype上的所有属性和方法。
  //关于 prototype的学习:http://www.cnblogs.com/dolphinX/p/3286177.html
  Sub.prototype = Object.create(Super.prototype);
  //Sub构造函数修正,学习于https://www.cnblogs.com/SheilaSun/p/4397918.html
  Sub.prototype.constructor = Sub;
  Sub.cid = cid++;
  //通过vue的合并策略合并添加项到新的构造器上
  Sub.options = mergeOptions(
   Super.options,
   extendOptions
  );
  //缓存父构造器
  Sub['super'] = Super;

  // 处理props和computed响应式配置项
  if (Sub.options.props) {
   initProps$1(Sub);
  }
  if (Sub.options.computed) {
   initComputed$1(Sub);
  }

  // allow further extension/mixin/plugin usage
  Sub.extend = Super.extend;
  Sub.mixin = Super.mixin;
  Sub.use = Super.use;

  //在新的构造器上挂上vue的工具方法
  ASSET_TYPES.forEach(function (type) {
   Sub[type] = Super[type];
  });
  // enable recursive self-lookup
  if (name) {
   Sub.options.components[name] = Sub;
  }

  // keep a reference to the super options at extension time.
  // later at instantiation we can check if Super's options have
  // been updated.
  Sub.superOptions = Super.options;
  Sub.extendOptions = extendOptions;
  Sub.sealedOptions = extend({}, Sub.options);

  //缓存组件构造器在extendOptions上
  cachedCtors[SuperId] = Sub;
  return Sub
 };

vue.extend返回了一个带有附加Option的vue构造器。这个构造器被命名为Sub,等待render时候初始化。

initAssetRegisters完成之后,options下挂载了全局组件button-counter,如图:

Vue源码解读之Component组件注册的实现

接下来调用new Vue()渲染vue整体的生命周期

局部注册

如果不需要全局注册,或者是让组件使用在其它组件内,可以用选项对象的components属性实现局部注册。

注册方式

new Vue({
    el: '#components-demo',
    components:{
      'button-counter':{
        template:'#clickBtn',
        data: function () {
          return {
            count: 0
          }
        }
      }
    }
  })

具体过程

Vue局部组件注册也是通过initAssetRegisters()方法调用Vue.extend,不同的是在createComponent()时,initMixin()里面有判断

if (options && options._isComponent) {
   //因为Vue动态合并策略非常慢,并且内部组件的选项都不需要特殊处理。
   //调用initInternalComponent快捷方法,内部组件实例化。
   initInternalComponent(vm, options);
 }
 else {
   vm.$options = mergeOptions(
    resolveConstructorOptions(vm.constructor),
    options || {},
    vm
   );
  }
function initInternalComponent (vm, options) {
 var opts = vm.$options = Object.create(vm.constructor.options);
 // 这样做是因为它比动态枚举更快。
 var parentVnode = options._parentVnode;
 opts.parent = options.parent;
 opts._parentVnode = parentVnode;

 var vnodeComponentOptions = parentVnode.componentOptions;
 opts.propsData = vnodeComponentOptions.propsData;
 opts._parentListeners = vnodeComponentOptions.listeners;
 opts._renderChildren = vnodeComponentOptions.children;
 opts._componentTag = vnodeComponentOptions.tag;

 if (options.render) {
  opts.render = options.render;
  opts.staticRenderFns = options.staticRenderFns;
 }
}

opts的结构如图所示:

Vue源码解读之Component组件注册的实现

局部注册和全局注册不同的是,只有该类型的组件才可以访问局部注册的子组件,而全局注册是扩展到 Vue.options 下。在所有组件创建的过程中,都会从全局的 Vue.options.components 扩展到当前组件的 vm.$options.components 下,这就是全局注册的组件能被任意使用的原因。

组件名定义

定义组件名的方式有两种:

使用短横线形式

Vue.component('button-counter', {})

引用这个自定义元素时,必须用 <button-counter></button-counter>

使用驼峰的形式

Vue.component('buttonCounter', { })

此时在引用这个自定义元素时,两种命名方法都可以使用。也就是说,<buttonCounter><button-counter> 都是可行的。

注意,直接在 DOM (即非字符串的模板) 中使用时只有短横线是有效的。如下:

<div id="components-demo">
    <button-counter></button-counter>
</div>

可参考:https://www.jb51.net/article/144050.htm

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持码农之家。

以上就是本次给大家分享的关于java的全部知识点内容总结,大家还可以在下方相关文章里找到相关文章进一步学习,感谢大家的阅读和支持。

Vue 相关电子书
学习笔记
网友NO.193270

深入理解vue-class-component源码阅读

vue-class-component是vue作者尤大推出的一个支持使用class方式来开发vue单文件组件的库。但是,在使用过程中我却发现了几个奇怪的地方。 首先,我们看一个简单的使用例子: // App.vuescriptimport Vue from 'vue'import Component from 'vue-class-component'@Component({ props: { propMessage: String }})export default class App extends Vue { // initial data msg=123 // use prop values for initial data helloMsg='Hello, '+this.propMessage // lifecycle hook mounted () { this.greet() } // computed get computedMsg () { return'computed '+this.msg } // method greet () { alert('greeting: '+this.msg) }}/script//main.jsimport App from './App.vue'newVue({ el: '#app', router, store, components: { App }, template: 'App/'}) 在这个例子中,很容易发现几个疑点: 1. App类居然没有constructor构造函数; 2. 导出的类居然没有被new就直接使用了。 3. msg=123,这是什么语法? 首先,针对前两个疑问,需要说明一……

网友NO.373402

关于vue.extend和vue.component的区别浅析

前言 最近一个朋友问我vue.extend和vue.component两者之间有什么区别?突然这么一问竟答不出来,回来想想有必要总结下,所以本文就来给大家介绍关于vue.extend和vue.component的区别,下面话不多说了,来一起看看详细的介绍吧。 Vue.extend 返回的是一个“扩展实例构造器”,也就是一个预设了部分选项的 Vue 实例构造器 var myVue = Vue.extend({ // 预设选项}) // 返回一个“扩展实例构造器”// 然后就可以这样来使用var vm = new myVue({ // 其他选项}) Vue.component 是用来全局注册组件的方法,其作用是将通过 Vue.extend 生成的扩展实例构造器注册(命名)为一个组件,可以简单理解为当在模板中遇到该组件名称作为标签的自定义元素时,会自动调用类似于 new myVue 这样的构造函数来生成组件实例,并挂载到自定义元素上,当然实际情况要比这复杂得多,还需要处理 props 数据传递……

网友NO.286384

vue19 组建 Vue.extend component、组件模版、动态组件 的实例代码

具体代码如下所示: !DOCTYPE htmlhtml lang="en"head meta charset="UTF-8" titleDocument/title script src="bower_components/vue/dist/vue.js"/script style /style/headbody div id="box" /div script var Aaa=Vue.extend({//继承出来一个Vue类Aaa template:'h3我是标题3/h3' }); var a=new Aaa();//a跟vm一样 console.log(a); var vm=new Vue({ el:'#box', data:{ bSign:true } }); /script/body/html !DOCTYPE htmlhtml lang="en"head meta charset="UTF-8" titleDocument/title script src="bower_components/vue/dist/vue.js"/script style /style/headbody div id="box" aaa/aaa /div script var Aaa=Vue.extend({ template:'h3我是标题3/h3' }); Vue.component('aaa',Aaa);//aaa是组建实例,全局组件 var vm=new Vue({ el:'#box', data:{ bSign:true } }); /script/body/html !DOCTYPE htmlhtml lang="en"head meta charset="UTF-8" titleDocument/title script src="bower_components/vue/dist/vue.js"/script style /style/headbody div id="box" aaa/aaa /div script var Aaa=Vue.extend({ data(){ return { msg:'我是标……

网友NO.923723

详解TypeScript+Vue 插件 vue-class-component的使用总结

首先 下载 npm install vue-class-component vue-property-decorator --save-dev 一梭子直接干; 其次,咱来说说它们的区别与联系: vue-property-decorator社区出品;vue-class-component官方出品 vue-class-component提供了Vue、Component等; vue-property-decorator深度依赖了vue-class-component,拓展出了更多操作符:@Prop、@Emit、@Inject、@Model、@Provide、@Watch; 开发时正常引入vue-property-decorator就行 引入后写vue代码就是如此, import {Component, Prop, Vue} from 'vue-property-decorator'@Componentexport default class App extends Vue { name:string = 'Simon Zhang' // computed get MyName():string { return `My name is ${this.name}` } // methods sayHello():void { alert(`Hello ${this.name}`) } mounted() { this.sayHello(); }} 相当于 export default { data () { return { name: 'Simon Zhang' } }, mounted () { this.sayHello() }, computed: { MyName() { return `My name is ${this.name}` } }, methods: { sayHello() { alert(`Hello $……

<
1
>

电子书 编程教程 PC软件下载 安卓软件下载

Copyright 2018-2020 xz577.com 码农之家

本站所有电子书资源不再提供下载地址,只分享来路

免责声明:网站所有作品均由会员网上搜集共同更新,仅供读者预览及学习交流使用,下载后请24小时内删除

版权投诉 / 书籍推广 / 赞助:QQ:520161757