摘要:代碼如下核心這里會再次合并一下上的全局的一些指令或則組件或則過濾器到組件的構(gòu)造函數(shù)上最后在內(nèi)部組件初始化時。會調(diào)用這里還是把構(gòu)造函數(shù)的放在了上供后續(xù)使用總的來說。將原型指向根構(gòu)造函數(shù)的自然而然就會有的原型上的所有屬性和方法。。
插件:聰明的程序員往往希望能更高(tou)效(lan)的完成指定的工作,插件就是按照一定的封裝方式,暴露接口。讓我們利用這些接口更快捷的實現(xiàn)功能。升職加薪。每個框架都提供了插件的擴(kuò)展機(jī)制。這是框架可擴(kuò)展性必不可少的一個部分。插件機(jī)制越簡單。對于框架的生態(tài)的發(fā)展大有好處。jquery提供了$.fn.extend,angular有對應(yīng)的依賴注入,module機(jī)制。既然vue那么精美,能迅速火起來。插件這部分的可擴(kuò)展性必須頂級。這里接下來我們看看vue插件的入侵機(jī)制。
說到插件。我們最多使用的一個方法。無非就是 Vue.use(MyPlugin, { someOption: true });
這么說的話,這個方法應(yīng)該是所有插件入侵vue的起點。沒錯。那么我們來看看這個方法:
Vue.use = function (plugin) { /* istanbul ignore if */ if (plugin.installed) { return//假如插件已經(jīng)初始化過就不再繼續(xù)。避免插件重復(fù)入侵 } // additional parameters var args = toArray(arguments, 1);//獲取插件的配置參數(shù) args.unshift(this); if (typeof plugin.install === "function") { plugin.install.apply(plugin, args);//調(diào)用的是插件的install方法; } else if (typeof plugin === "function") { plugin.apply(null, args);//若插件本省就是一個函數(shù)。則直接調(diào)用該函數(shù) } plugin.installed = true; return this };
Vue.use這個方法讓我們知道來。插件入侵的起點是調(diào)用插件自身的install函數(shù)。那么不同的插件入侵的機(jī)制有些時候很不一樣。我們可以知道。這個不一樣肯定發(fā)生在install函數(shù)中。我們來看看官方的install函數(shù)中的一些方式:
MyPlugin.install = function (Vue, options) { // 1. 添加全局方法或?qū)傩? Vue.myGlobalMethod = function () { // 邏輯... } // 2. 添加全局資源 Vue.directive("my-directive", { bind (el, binding, vnode, oldVnode) { // 邏輯... } ... }) // 3. 注入組件 Vue.mixin({ created: function () { // 邏輯... } ... }) // 4. 添加實例方法 Vue.prototype.$myMethod = function (options) { // 邏輯... } }
我們按官網(wǎng)推薦的四種例子。來看看每種方法對應(yīng)的源碼:
1:Vue.myGlobalMethod = function () { // 邏輯... }
類似jquery中的jquery.myGlobalMethod或則$.myGlobalMethod簡單來說就是給Vue這個全局對象添加一些工具方法??梢怨┤挚旖菡{(diào)用。我們這里就略過了
2: // 2. 添加全局資源 Vue.directive("my-directive", { bind (el, binding, vnode, oldVnode) { // 邏輯... } ... })
Vue.directive,Vue.filter,Vue.component等價。當(dāng)全局使用這些api時。會在vue上把這些指令過濾器組件等放在相應(yīng)的屬性數(shù)組里。形如:
Vue.options = { components: { }, directives: {}, filters: {}, _base: Vue }
因為他掛在全局的vue中。在vue初始化。調(diào)用init方法時。會執(zhí)行:
vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor),//策略合并核心函數(shù)??梢宰屑?xì)去看看 options || {}, vm );
vue在創(chuàng)建實例時。會把vue對象上的options的對象中的屬性提取出來和傳入的options做合并。這里涉及到合并策略。以后會專門講一下。這里只要知道。vue每個配置相都有自己的合并規(guī)則。mergeOptions會根據(jù)合并的類目去選擇對應(yīng)的合并規(guī)則。這里的component.directive.filter根據(jù)合并規(guī)則。Vue對象上的全局的這些屬性會被放在實例的__proto__上。
同樣的。相應(yīng)的子組件??梢曰剡^頭去看一下組件那一章。在render創(chuàng)建子組件的時候。代碼如下:
function createComponent ( Ctor, data, context, children, tag ) { if (isUndef(Ctor)) { return } var baseCtor = context.$options._base; // plain options object: turn it into a constructor if (isObject(Ctor)) { Ctor = baseCtor.extend(Ctor); } // if at this stage it"s not a constructor or an async component factory, // reject. if (typeof Ctor !== "function") { { warn(("Invalid Component definition: " + (String(Ctor))), context); } return } // async component if (isUndef(Ctor.cid)) { Ctor = resolveAsyncComponent(Ctor, baseCtor, context); if (Ctor === undefined) { // return nothing if this is indeed an async component // wait for the callback to trigger parent update. return } } // resolve constructor options in case global mixins are applied after // component constructor creation resolveConstructorOptions(Ctor);//核心:這里會再次合并一下vue上的全局的一些指令或則組件或則過濾器到組件的構(gòu)造函數(shù)上 data = data || {}; // transform component v-model data into props & events if (isDef(data.model)) { transformModel(Ctor.options, data); } // extract props var propsData = extractPropsFromVNodeData(data, Ctor, tag); // functional component if (isTrue(Ctor.options.functional)) { return createFunctionalComponent(Ctor, propsData, data, context, children) } // extract listeners, since these needs to be treated as // child component listeners instead of DOM listeners var listeners = data.on; // replace with listeners with .native modifier data.on = data.nativeOn; if (isTrue(Ctor.options.abstract)) { // abstract components do not keep anything // other than props & listeners data = {}; } // merge component management hooks onto the placeholder node mergeHooks(data); // return a placeholder vnode var name = Ctor.options.name || tag; var vnode = new VNode( ("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : "")), data, undefined, undefined, undefined, context, { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children } ); return vnode }
最后在內(nèi)部組件初始化時。vue會調(diào)用
function initInternalComponent (vm, options) { var opts = vm.$options = Object.create(vm.constructor.options);//這里還是把構(gòu)造函數(shù)的options放在了$options上供后續(xù)使用 // doing this because it"s faster than dynamic enumeration. opts.parent = options.parent; opts.propsData = options.propsData; opts._parentVnode = options._parentVnode; opts._parentListeners = options._parentListeners; opts._renderChildren = options._renderChildren; opts._componentTag = options._componentTag; opts._parentElm = options._parentElm; opts._refElm = options._refElm; if (options.render) { opts.render = options.render; opts.staticRenderFns = options.staticRenderFns; } }
總的來說。如果是全局的指令過濾器時。vue統(tǒng)一把他放在根構(gòu)造方法上。根實例初始化時。通過策略合并合并到$options中。而子組件稍微繞了一下。最終也是放在$options的原型上。很連貫啊。這樣只要是全局的組件。指令過濾器。每個子組件都可以繼承使用。達(dá)到了插件的效果。
3:下面來看看mixin方法:
Vue.mixin({ created: function () { // 邏輯... } ... }) Vue.mixin = function (mixin) { this.options = mergeOptions(this.options, mixin); }; //這里還是不可避免要看看mergeOptions函數(shù): function mergeOptions ( parent, child, vm ) { { checkComponents(child); } if (typeof child === "function") { child = child.options; } normalizeProps(child); normalizeDirectives(child); var extendsFrom = child.extends; if (extendsFrom) { parent = mergeOptions(parent, extendsFrom, vm); } if (child.mixins) { for (var i = 0, l = child.mixins.length; i < l; i++) { parent = mergeOptions(parent, child.mixins[i], vm); } } var options = {}; var key; for (key in parent) { mergeField(key); } for (key in child) { if (!hasOwn(parent, key)) { mergeField(key); } } function mergeField (key) { var strat = strats[key] || defaultStrat; options[key] = strat(parent[key], child[key], vm, key); } return options }
分兩種情況吧:
a:全局注冊時即vue.mixin時。直接調(diào)用合并。直接便利mixin中的項目。分別調(diào)用相應(yīng)合并策略。合并到構(gòu)造函數(shù)的options中。影響后面所有的子組件
b:局部注冊時。
if (child.mixins) { for (var i = 0, l = child.mixins.length; i < l; i++) { parent = mergeOptions(parent, child.mixins[i], vm); } }
則會去遞歸的調(diào)用合并策略把該合并的項目合并結(jié)束為止;
vue.mixin就相當(dāng)于是一個傳入的額外的配置項目,會讓vue重新按照規(guī)則合并一次,成功入侵vue
4:
// 4. 添加實例方法 Vue.prototype.$myMethod = function (options) { // 邏輯... }
這個方法就很明顯了。在vue的原型上掛載方法。vue的實例自然而然就能繼承。子組件在創(chuàng)建的時候。
Sub.prototype = Object.create(Super.prototype); Sub.prototype.constructor = Sub;
將原型指向根構(gòu)造函數(shù)Vue的prototype;自然而然就會有Vue的原型上的所有屬性和方法。。
以上就是vue比較常用的插件侵入方法。哈哈。下次再說。告辭
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/83494.html
前言 從 9 月份開始,vuepress 源碼進(jìn)行了重新設(shè)計和拆分。先是開了個 next 分支,后來又合并到 master 分支,為即將發(fā)布的 1.x 版本做準(zhǔn)備。 最主要的變化是:大部分的全局功能都被拆分成了插件的形式,以可插拔的方式來支撐 vuepress 的運作,這一點很像 webpack。 具體架構(gòu)如下: showImg(https://user-gold-cdn.xitu.io/2019...
摘要:毫無疑問,設(shè)計模式于己于他人于系統(tǒng)都是多贏的設(shè)計模式使代碼編寫真正工程化設(shè)計模小書前端掘金這是一本關(guān)于的小書。 JavaScript 常見設(shè)計模式解析 - 掘金設(shè)計模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計經(jīng)驗的總結(jié)。使用設(shè)計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。毫無疑問,設(shè)計模式于己于他人于系統(tǒng)都是多贏的;設(shè)計...
摘要:慢慢地,關(guān)于的原創(chuàng)學(xué)習(xí)文章已經(jīng)寫了多篇了會一直放出來,目前篇,因此做一個合集,獻(xiàn)給那些對新版本腳手架使用和背后設(shè)計感興趣的同學(xué),都是一步一步去看源碼,也給官方提了幾次,合進(jìn)去了幾個原創(chuàng)不易,歡迎大家互相轉(zhuǎn)發(fā),期望大家一起快速過度到版本目錄 慢慢地,關(guān)于 Vue CLI 3 的原創(chuàng)學(xué)習(xí)文章已經(jīng)寫了 20 多篇了(會一直放出來,目前 23 篇), 因此做一個合集,獻(xiàn)給那些對新版本腳手架使用...
閱讀 2485·2021-11-19 09:59
閱讀 2016·2019-08-30 15:55
閱讀 942·2019-08-29 13:30
閱讀 1348·2019-08-26 10:18
閱讀 3094·2019-08-23 18:36
閱讀 2396·2019-08-23 18:25
閱讀 1169·2019-08-23 18:07
閱讀 446·2019-08-23 17:15