這里給大家分享我在網(wǎng)上總結(jié)出來的一些知識,希望對大家有所幫助
一、mixin是什么
Mixin
是面向?qū)ο蟪绦蛟O(shè)計語言中的類,提供了方法的實現(xiàn)。其他類可以訪問mixin
類的方法而不必成為其子類
Mixin
類通常作為功能模塊使用,在需要該功能時“混入”,有利于代碼復(fù)用又避免了多繼承的復(fù)雜
Vue中的mixin
先來看一下官方定義
mixin
(混入),提供了一種非常靈活的方式,來分發(fā)?Vue
?組件中的可復(fù)用功能。
本質(zhì)其實就是一個js
對象,它可以包含我們組件中任意功能選項,如data
、components
、methods
、created
、computed
等等
我們只要將共用的功能以對象的方式傳入?mixins
選項中,當(dāng)組件使用?mixins
對象時所有mixins
對象的選項都將被混入該組件本身的選項中來
在Vue
中我們可以局部混入跟全局混入
局部混入
定義一個mixin
對象,有組件options
的data
、methods
屬性
var myMixin = { created: function () { this.hello() }, methods: { hello: function () { console.log('hello from mixin!') } } }
組件通過mixins
屬性調(diào)用mixin
對象
Vue.component('componentA',{ mixins: [myMixin] })
該組件在使用的時候,混合了mixin
里面的方法,在自動執(zhí)行created
生命鉤子,執(zhí)行hello
方法
全局混入
通過Vue.mixin()
進行全局的混入
Vue.mixin({ created: function () { console.log("全局混入") } })
使用全局混入需要特別注意,因為它會影響到每一個組件實例(包括第三方組件)
PS:全局混入常用于插件的編寫
注意事項:
當(dāng)組件存在與mixin
對象相同的選項的時候,進行遞歸合并的時候組件的選項會覆蓋mixin
的選項
但是如果相同選項為生命周期鉤子的時候,會合并成一個數(shù)組,先執(zhí)行mixin
的鉤子,再執(zhí)行組件的鉤子
二、使用場景
在日常的開發(fā)中,我們經(jīng)常會遇到在不同的組件中經(jīng)常會需要用到一些相同或者相似的代碼,這些代碼的功能相對獨立
這時,可以通過Vue
的mixin
功能將相同或者相似的代碼提出來
舉個例子
定義一個modal
彈窗組件,內(nèi)部通過isShowing
來控制顯示
const Modal = { template: '#modal', data() { return { isShowing: false } }, methods: { toggleShow() { this.isShowing = !this.isShowing; } } }
定義一個tooltip
提示框,內(nèi)部通過isShowing
來控制顯示
const Tooltip = { template: '#tooltip', data() { return { isShowing: false } }, methods: { toggleShow() { this.isShowing = !this.isShowing; } } }
通過觀察上面兩個組件,發(fā)現(xiàn)兩者的邏輯是相同,代碼控制顯示也是相同的,這時候mixin
就派上用場了
首先抽出共同代碼,編寫一個mixin
const toggle = { data() { return { isShowing: false } }, methods: { toggleShow() { this.isShowing = !this.isShowing; } } }
兩個組件在使用上,只需要引入mixin
const Modal = { template: '#modal', mixins: [toggle] }; const Tooltip = { template: '#tooltip', mixins: [toggle] }
通過上面小小的例子,讓我們知道了Mixin
對于封裝一些可復(fù)用的功能如此有趣、方便、實用
三、源碼分析
首先從Vue.mixin
入手
源碼位置:/src/core/global-api/mixin.js
export function initMixin (Vue: GlobalAPI) { Vue.mixin = function (mixin: Object) { this.options = mergeOptions(this.options, mixin) return this } }
主要是調(diào)用merOptions
方法
源碼位置:/src/core/util/options.js
export function mergeOptions ( parent: Object, child: Object, vm?: Component ): Object { if (child.mixins) { // 判斷有沒有mixin 也就是mixin里面掛mixin的情況 有的話遞歸進行合并 for (let i = 0, l = child.mixins.length; i < l; i++) { parent = mergeOptions(parent, child.mixins[i], vm) } } const options = {} let key for (key in parent) { mergeField(key) // 先遍歷parent的key 調(diào)對應(yīng)的strats[XXX]方法進行合并 } for (key in child) { if (!hasOwn(parent, key)) { // 如果parent已經(jīng)處理過某個key 就不處理了 mergeField(key) // 處理child中的key 也就parent中沒有處理過的key } } function mergeField (key) { const strat = strats[key] || defaultStrat options[key] = strat(parent[key], child[key], vm, key) // 根據(jù)不同類型的options調(diào)用strats中不同的方法進行合并 } return options }
從上面的源碼,我們得到以下幾點:
- 優(yōu)先遞歸處理?
mixins
- 先遍歷合并
parent
?中的key
,調(diào)用mergeField
方法進行合并,然后保存在變量options
- 再遍歷?
child
,合并補上?parent
?中沒有的key
,調(diào)用mergeField
方法進行合并,保存在變量options
- 通過?
mergeField
?函數(shù)進行了合并
下面是關(guān)于Vue
的幾種類型的合并策略
- 替換型
- 合并型
- 隊列型
- 疊加型
替換型
替換型合并有props
、methods
、inject
、computed
strats.props = strats.methods = strats.inject = strats.computed = function ( parentVal: ?Object, childVal: ?Object, vm?: Component, key: string ): ?Object { if (!parentVal) return childVal // 如果parentVal沒有值,直接返回childVal const ret = Object.create(null) // 創(chuàng)建一個第三方對象 ret extend(ret, parentVal) // extend方法實際是把parentVal的屬性復(fù)制到ret中 if (childVal) extend(ret, childVal) // 把childVal的屬性復(fù)制到ret中 return ret } strats.provide = mergeDataOrFn
同名的props
、methods
、inject
、computed
會被后來者代替
合并型
和并型合并有:data
strats.data = function(parentVal, childVal, vm) { return mergeDataOrFn( parentVal, childVal, vm ) }; function mergeDataOrFn(parentVal, childVal, vm) { return function mergedInstanceDataFn() { var childData = childVal.call(vm, vm) // 執(zhí)行data掛的函數(shù)得到對象 var parentData = parentVal.call(vm, vm) if (childData) { return mergeData(childData, parentData) // 將2個對象進行合并 } else { return parentData // 如果沒有childData 直接返回parentData } } } function mergeData(to, from) { if (!from) return to var key, toVal, fromVal; var keys = Object.keys(from); for (var i = 0; i < keys.length; i++) { key = keys[i]; toVal = to[key]; fromVal = from[key]; // 如果不存在這個屬性,就重新設(shè)置 if (!to.hasOwnProperty(key)) { set(to, key, fromVal); } // 存在相同屬性,合并對象 else if (typeof toVal =="object" && typeof fromVal =="object") { mergeData(toVal, fromVal); } } return to }
mergeData
函數(shù)遍歷了要合并的 data 的所有屬性,然后根據(jù)不同情況進行合并:
- 當(dāng)目標(biāo) data 對象不包含當(dāng)前屬性時,調(diào)用?
set
?方法進行合并(set方法其實就是一些合并重新賦值的方法) - 當(dāng)目標(biāo) data 對象包含當(dāng)前屬性并且當(dāng)前值為純對象時,遞歸合并當(dāng)前對象值,這樣做是為了防止對象存在新增屬性
隊列性
隊列性合并有:全部生命周期和watch
function mergeHook ( parentVal: ?Array<Function>, childVal: ?Function | ?Array<Function> ): ?Array<Function> { return childVal ? parentVal ? parentVal.concat(childVal) : Array.isArray(childVal) ? childVal : [childVal] : parentVal } LIFECYCLE_HOOKS.forEach(hook => { strats[hook] = mergeHook }) // watch strats.watch = function ( parentVal, childVal, vm, key ) { // work around Firefox's Object.prototype.watch... if (parentVal === nativeWatch) { parentVal = undefined; } if (childVal === nativeWatch) { childVal = undefined; } /* istanbul ignore if */ if (!childVal) { return Object.create(parentVal || null) } { assertObjectType(key, childVal, vm); } if (!parentVal) { return childVal } var ret = {}; extend(ret, parentVal); for (var key$1 in childVal) { var parent = ret[key$1]; var child = childVal[key$1]; if (parent && !Array.isArray(parent)) { parent = [parent]; } ret[key$1] = parent ? parent.concat(child) : Array.isArray(child) ? child : [child]; } return ret };
生命周期鉤子和watch
被合并為一個數(shù)組,然后正序遍歷一次執(zhí)行
疊加型
疊加型合并有:component
、directives
、filters
文章來源:http://www.zghlxwxcb.cn/news/detail-837817.html
strats.components= strats.directives= strats.filters = function mergeAssets( parentVal, childVal, vm, key ) { var res = Object.create(parentVal || null); if (childVal) { for (var key in childVal) { res[key] = childVal[key]; } } return res }
疊加型主要是通過原型鏈進行層層的疊加文章來源地址http://www.zghlxwxcb.cn/news/detail-837817.html
小結(jié):
- 替換型策略有
props
、methods
、inject
、computed
,就是將新的同名參數(shù)替代舊的參數(shù) - 合并型策略是
data
, 通過set
方法進行合并和重新賦值 - 隊列型策略有生命周期函數(shù)和
watch
,原理是將函數(shù)存入一個數(shù)組,然后正序遍歷依次執(zhí)行 - 疊加型有
component
、directives
、filters
,通過原型鏈進行層層的疊加
參考文獻(xiàn)
- https://zhuanlan.zhihu.com/p/31018570
- https://juejin.cn/post/6844904015495446536#heading-1
- https://juejin.cn/post/6844903846775357453
- https://vue3js.cn/docs/zh
到了這里,關(guān)于說說你對vue的mixin的理解,有什么應(yīng)用場景?的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!