什么是組件?
創(chuàng)新互聯(lián)提供網(wǎng)站制作、成都網(wǎng)站制作、網(wǎng)頁(yè)設(shè)計(jì),品牌網(wǎng)站設(shè)計(jì),1元廣告等致力于企業(yè)網(wǎng)站建設(shè)與公司網(wǎng)站制作,10多年的網(wǎng)站開(kāi)發(fā)和建站經(jīng)驗(yàn),助力企業(yè)信息化建設(shè),成功案例突破上1000+,是您實(shí)現(xiàn)網(wǎng)站建設(shè)的好選擇.
組件 (Component) 是 Vue.js 最強(qiáng)大的功能之一。組件可以擴(kuò)展 HTML 元素,封裝可重用的代碼。在較高層面上,組件是自定義元素,Vue.js 的編譯器為它添加特殊功能。在有些情況下,組件也可以表現(xiàn)為用 is 特性進(jìn)行了擴(kuò)展的原生 HTML 元素。
所有的 Vue 組件同時(shí)也都是 Vue 的實(shí)例,所以可接受相同的選項(xiàng)對(duì)象 (除了一些根級(jí)特有的選項(xiàng)) 并提供相同的生命周期鉤子。
Vue可以有全局注冊(cè)和局部注冊(cè)兩種方式來(lái)注冊(cè)組件。
全局注冊(cè)
注冊(cè)方式
全局注冊(cè)有以下兩種注冊(cè)方式:
通過(guò)Vue.component 直接注冊(cè)。
Vue.component('button-counter', { //data選項(xiàng)必須是一個(gè)函數(shù) data: function () { return { count: 0 } }, template:'#clickBtn' })
通過(guò)Vue.extend來(lái)注冊(cè)。
var buttonComponent = Vue.extend({ name:'button-counter', data: function () { return { count: 0 } }, template:'#clickBtn' }); Vue.component('button-counter', buttonComponent);
具體過(guò)程
Vue初始化時(shí),initGlobalAPI通過(guò)調(diào)用initAssetRegisters()進(jìn)行組件注冊(cè)。
function initAssetRegisters (Vue) { // 創(chuàng)建組件注冊(cè)的方法 // ASSET_TYPES在Vue內(nèi)部定義,var ASSET_TYPES = ['component','directive','filter']; ASSET_TYPES.forEach(function (type) { Vue[type] = function ( id, definition ) { //這里的definition指的是定義(Function或Object),是函數(shù)或者對(duì)象 //如果definition不存在,直接返回options內(nèi)type和id對(duì)應(yīng)的 //這里的options是指全局的組件,指令和過(guò)濾器,見(jiàn)圖一 if (!definition) { return this.options[type + 's'][id] } else { /* istanbul ignore if */ if ("development" !== 'production' && type === 'component') { validateComponentName(id); } // 如果是component(組件)方法,并且definition是對(duì)象 if (type === 'component' && isPlainObject(definition)) { definition.name = definition.name || id; //通過(guò)this.options._base.extend方法(也就是Vue.extend方法)將定義對(duì)象轉(zhuǎn)化為構(gòu)造器。 //Vue.options._base = Vue; definition = this.options._base.extend(definition); } if (type === 'directive' && typeof definition === 'function') { definition = { bind: definition, update: definition }; } // 將構(gòu)造器賦值給 this.options[‘component'+ 's'][id] //全局的組件,指令和過(guò)濾器,統(tǒng)一掛在vue.options上。在init的時(shí)候利用mergeOptions合并策略侵入實(shí)例,供實(shí)例使用。 this.options[type + 's'][id] = definition; return definition } }; }); }
圖一:
initAssetRegisters里面通過(guò)this.options._base.extend方法將定義對(duì)象轉(zhuǎn)化為構(gòu)造器,而options._base.extend其實(shí)就是Vue.extend。接下來(lái)我們就看一下Vue.extend做了什么。
Vue.extend = function (extendOptions) { extendOptions = extendOptions || {}; var Super = this; var SuperId = Super.cid; //組件緩存 var cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {}); //如果組件已經(jīng)被緩存在extendOptions上則直接取出 if (cachedCtors[SuperId]) { return cachedCtors[SuperId] } //如果有name屬性,檢驗(yàn)name拼寫(xiě)是否合法 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的實(shí)例同時(shí)也繼承了vue.prototype上的所有屬性和方法。 //關(guān)于 prototype的學(xué)習(xí):http://www.cnblogs.com/dolphinX/p/3286177.html Sub.prototype = Object.create(Super.prototype); //Sub構(gòu)造函數(shù)修正,學(xué)習(xí)于https://www.cnblogs.com/SheilaSun/p/4397918.html Sub.prototype.constructor = Sub; Sub.cid = cid++; //通過(guò)vue的合并策略合并添加項(xiàng)到新的構(gòu)造器上 Sub.options = mergeOptions( Super.options, extendOptions ); //緩存父構(gòu)造器 Sub['super'] = Super; // 處理props和computed響應(yīng)式配置項(xiàng) 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; //在新的構(gòu)造器上掛上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); //緩存組件構(gòu)造器在extendOptions上 cachedCtors[SuperId] = Sub; return Sub };
vue.extend返回了一個(gè)帶有附加Option的vue構(gòu)造器。這個(gè)構(gòu)造器被命名為Sub,等待render時(shí)候初始化。
initAssetRegisters完成之后,options下掛載了全局組件button-counter,如圖:
接下來(lái)調(diào)用new Vue()渲染vue整體的生命周期
局部注冊(cè)
如果不需要全局注冊(cè),或者是讓組件使用在其它組件內(nèi),可以用選項(xiàng)對(duì)象的components屬性實(shí)現(xiàn)局部注冊(cè)。
注冊(cè)方式
new Vue({ el: '#components-demo', components:{ 'button-counter':{ template:'#clickBtn', data: function () { return { count: 0 } } } } })
具體過(guò)程
Vue局部組件注冊(cè)也是通過(guò)initAssetRegisters()方法調(diào)用Vue.extend,不同的是在createComponent()時(shí),initMixin()里面有判斷
if (options && options._isComponent) { //因?yàn)閂ue動(dòng)態(tài)合并策略非常慢,并且內(nèi)部組件的選項(xiàng)都不需要特殊處理。 //調(diào)用initInternalComponent快捷方法,內(nèi)部組件實(shí)例化。 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); // 這樣做是因?yàn)樗葎?dòng)態(tài)枚舉更快。 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的結(jié)構(gòu)如圖所示:
局部注冊(cè)和全局注冊(cè)不同的是,只有該類(lèi)型的組件才可以訪問(wèn)局部注冊(cè)的子組件,而全局注冊(cè)是擴(kuò)展到 Vue.options 下。在所有組件創(chuàng)建的過(guò)程中,都會(huì)從全局的 Vue.options.components 擴(kuò)展到當(dāng)前組件的 vm.$options.components 下,這就是全局注冊(cè)的組件能被任意使用的原因。
組件名定義
定義組件名的方式有兩種:
使用短橫線形式
Vue.component('button-counter', {})
引用這個(gè)自定義元素時(shí),必須用
使用駝峰的形式
Vue.component('buttonCounter', { })
此時(shí)在引用這個(gè)自定義元素時(shí),兩種命名方法都可以使用。也就是說(shuō),
和
都是可行的。
注意,直接在 DOM (即非字符串的模板) 中使用時(shí)只有短橫線是有效的。如下:
可參考:https://www.jb51.net/article/144050.htm
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。