在項(xiàng)目中 mixins
(混合)特性使用頻率是很高的 有必要熟練掌握
官網(wǎng)傳送門(mén):mixins
# 簡(jiǎn)介
? 混入(mixins
)是一種分發(fā)Vue組件中可復(fù)用功能的非常靈活的方式,它的存在使得開(kāi)發(fā)者們可以定義一部分公用的屬性或方法,然后混入到各個(gè)組件內(nèi)部使用弊攘,提高了可維護(hù)性涩哟。
? 一個(gè)混入自身以一個(gè)對(duì)象的形式存在吧慢,如var mixin = { }
驹马,它可以包含任意組件選項(xiàng)卷拘。在調(diào)用方中仰禽,調(diào)用混入對(duì)象使用mixins: []
氮墨,接收一個(gè)混入對(duì)象的數(shù)組,也就是說(shuō)可以一次混入多個(gè)混入對(duì)象吐葵。
# 混入選項(xiàng)合并
? 當(dāng)組件使用混入對(duì)象時(shí)规揪,所有混入對(duì)象的選項(xiàng)將被混入該組件本身的選項(xiàng)中。
?先看案例再理解
'# file: mixins/welcome.js'
export const Welcome = {
created: {
this.initPage();
},
methods: {
initPage() {
this.$toast('icon-welcome', '正在進(jìn)入系統(tǒng)温峭,請(qǐng)稍后...')
}
}
}
在組件中混入如上混入對(duì)象
import { Welcome } from '../assets/js/mixins/welcome'
export default {
name: 'AnyComponent',
mixins: [ Welcome ],
data () {
return {
greet: '正在進(jìn)入業(yè)務(wù)系統(tǒng)猛铅,請(qǐng)稍后...'
}
},
created: {
this.initPage()
},
methods: {
initPage() {
this.$toast('icon-welcome', this.greet)
}
}
}
----------------------
# 執(zhí)行結(jié)果
正在進(jìn)入業(yè)務(wù)系統(tǒng),請(qǐng)稍后...
正在進(jìn)入業(yè)務(wù)系統(tǒng)凤藏,請(qǐng)稍后...
? 對(duì)此結(jié)果或許會(huì)感到疑惑奸忽,那是因?yàn)橛腥缦禄烊胍?guī)則:
- data選項(xiàng)在混入時(shí),數(shù)據(jù)對(duì)象在內(nèi)部會(huì)進(jìn)行遞歸合并揖庄,當(dāng)發(fā)生沖突時(shí)栗菜,以組件數(shù)據(jù)優(yōu)先
- 同名鉤子函數(shù)混合為一個(gè)數(shù)組,兩個(gè)鉤子函數(shù)內(nèi)部的邏輯都會(huì)被執(zhí)行蹄梢,且混入的比組件的先調(diào)用
-
值為對(duì)象的選項(xiàng)如
methods, components, directives
將被 混合為同一個(gè)對(duì)象疙筹。沖突取組件鍵值對(duì) - 自定義的混入策略,見(jiàn)后續(xù)
再來(lái)理解以上案例,created
鉤子混入后兩個(gè)方法調(diào)用都會(huì)執(zhí)行腌歉,而methods
因?yàn)榛烊霑r(shí)鍵沖突以組件為主蛙酪,因此有了以上輸出。
# 自定義混入策略
? 如果想讓自定義選項(xiàng)使用自定義邏輯混入合并翘盖,可以向Vue.config.optionMessageStrategies
添加一個(gè)函數(shù)桂塞,例如自定義選項(xiàng)名為myOption
則
Vue.config.optionMessageStrategies.myOption = function (toVal, fromVal) {
// return mergeVal
}
? 對(duì)于大多數(shù)自定義的對(duì)象型選項(xiàng)來(lái)說(shuō),直接復(fù)用methods
的即可
var strategies = Vue.config.optionMergeStrategies
strategies.myOption = strategies.methods
舉一個(gè)vuex的混入案例如下馍驯,復(fù)用了computed
的混入規(guī)則
const merge = Vue.config.optionMergeStrategies.computed
Vue.config.optionMergeStrategies.vuex = function (toVal, fromVal) {
if (!toVal) return fromVal
if (!fromVal) return toVal
return {
getters: merge(toVal.getters, fromVal.getters),
state: merge(toVal.state, fromVal.state),
actions: merge(toVal.actions, fromVal.actions)
}
}
?
# 經(jīng)典案例高級(jí)用法
? 實(shí)際項(xiàng)目中一般都會(huì)存在 列表(List)
這種很常見(jiàn)的案例阁危,本文將介紹怎么利用mixin
來(lái)實(shí)現(xiàn)一個(gè)能高復(fù)用的混入模型,并拆解分析各個(gè)步驟要點(diǎn)
$ 代碼及設(shè)計(jì)
- file: assets/mixins/list.js
module.exports = {
data () {
return {
list: [], // 列表數(shù)據(jù)
page: 1, // 當(dāng)前頁(yè)碼
limit: 10, // 單頁(yè)條數(shù)
total: 0 // 總條數(shù)
}
},
created () {
this.initList()
},
watch: {
page: 'loadData'
},
methods: {
/**
* @func 獲取請(qǐng)求參數(shù) 默認(rèn)只傳遞index, limit汰瘫。也可以由外部構(gòu)建合并參數(shù)
* @param params
* @returns {*}
*/
getparams (params) {
return Object.assign({
index: this.page,
limit: this.limit
}, params)
},
/**
* @func 查詢(xún)結(jié)果壓入list狂打,注意Vue監(jiān)聽(tīng)的特性,更新數(shù)組應(yīng)用push混弥,有格式需要處理則傳入filter函數(shù)
* @param list-加載更多返回的數(shù)據(jù)列表, filter-數(shù)據(jù)過(guò)濾函數(shù)
*/
pushToList (list, filter) {
list.forEach(item => {
let it = typeof filter == 'function' ? filter(item) : item
this.list.push(it)
})
},
/**
* @func 加載更多
*/
loadMore () {
this.page++
},
/**
* @func 初始化列表
* /
initList () {
this.page = 1
this.list = []
this.loadData()
},
/**
* @overwrite
* @func 加載數(shù)據(jù)方法趴乡,組件中必須根據(jù)自己需要重寫(xiě)該方法,否則無(wú)法加載數(shù)據(jù)
*/
loadData () {
// please overwrite me
}
}
}
$ API 及 README
- 一個(gè)列表的基本屬性
屬性 | 作用或備注 |
---|---|
list | 列表 |
page | 頁(yè)碼 |
limit | 每頁(yè)條數(shù) |
total | 總條數(shù) |
- 基本方法
方法 | 作用或備注 |
---|---|
initList() | 初始化列表 |
loadData() | 加載數(shù)據(jù)(組件請(qǐng)重寫(xiě)) |
loadMore() | 加載更多 |
- 擴(kuò)展方法:主要用于參數(shù)或結(jié)果的處理
方法 | 作用或備注 |
---|---|
getParams() | 獲取HTTP請(qǐng)求參數(shù) |
pushToList() | 數(shù)據(jù)處理方法蝗拿,新數(shù)據(jù)入隊(duì)列 |
每一個(gè)列表結(jié)構(gòu)都具備的屬性以及方法 可以放到mixins
的聲明中
$ 提示:vue監(jiān)聽(tīng)數(shù)組變化
? Vue觀察數(shù)組變化主要通過(guò)以下7個(gè)方法(push晾捏、pop、shift哀托、unshift惦辛、splice、sort仓手、reverse
)胖齐,通過(guò)prototype
添加或下標(biāo)方式將不能成功被捕獲
$ 問(wèn)題:非初始化情況下使用
? 在keep-alive
的應(yīng)用下使用route-->data()
的鉤子中執(zhí)行初始化,會(huì)發(fā)現(xiàn)初始化了兩次
route: {
data () {
this.initList()
}
}
$ 原因:mixin
合并策略導(dǎo)致
? 因?yàn)榛烊胍?guī)則嗽冒,即使你在引用的組件中呀伙,把created
重寫(xiě),也是兩個(gè)都會(huì)執(zhí)行)辛慰,因?yàn)楹喜⒌牟呗圆煌瑢?dǎo)致了 methods
可以被重寫(xiě) 而created ready
等只會(huì)被合并区匠。
$ 解決辦法: 自定義選項(xiàng)
? 自定義選項(xiàng)doNotInit
干像,通過(guò)該選項(xiàng)來(lái)判斷是否需要在組件創(chuàng)建完畢之后就初始化
? 在調(diào)用該mixins
的組件中 添加這么一個(gè)選項(xiàng)帅腌,就可以讓組件判斷通過(guò)create初始化,還是通過(guò)route->data()鉤子來(lái)初始化
created () {
let option = this.$options.doNotInit
if (!option) {
this.initList()
}
}
$ 使用(調(diào)用)混入
- file: anyVueCompontent.vue
import List from './../assets/mixins/list'
export default {
mixins: [ List ],
data () {
return {
// 除列表外其他屬性
}
},
methods: {
loadData () {
this.$http.post(yourApiUrl, this.getParams()).then(res => {
// TODO: some logic
})
}
},
doNotInit: true, // 指定為created不執(zhí)行初始化
route: {
data () {
this.initList()
}
}
}