簡述
(本文針對于有Vue有一定基礎(chǔ)的人學(xué)習(xí)了解,環(huán)境搭建等入門教程網(wǎng)上很多,大家自行學(xué)習(xí),也可留言,我會(huì)給出一些不錯(cuò)的教程博客供大家學(xué)習(xí)。)
一、通過一個(gè)小demo,讓大家深入了解組件開發(fā)。并將教會(huì)大家以下知識(shí)。
- (特色) v-model 在自定義組件中的使用。在送索引擎中,搜索 v-model 相關(guān)知識(shí),絕大部分都是如何使用v-model這個(gè)指令進(jìn)行數(shù)據(jù)雙向綁定。然而,如何自定義一個(gè)組件,并且使用這個(gè)組件時(shí)可以用v-model,讓自己的組件也支持?jǐn)?shù)據(jù)雙向綁定,是一個(gè)問題,也很少有教程。
2.自定義組件,組件的使用。這部分內(nèi)容網(wǎng)絡(luò)上的教程很多,不作為重點(diǎn)介紹。
3.組件間的通訊。本章中將會(huì)使用$emit進(jìn)行父子組件中的通訊。并且提供工具類,降低耦合性。
4.<strong>(特色)兩個(gè)組件配合使用,完成特定功能</strong>兩個(gè)組件嵌套使用,完成效果和對數(shù)據(jù)的管理。
二、demo 說明
廢話不多說,先上效果圖。


實(shí)現(xiàn)思路,自定義兩個(gè)組件,一個(gè)標(biāo)簽組件“seltipoption”,方便使用v-for進(jìn)行渲染,一個(gè)父組件"seltiplist",管理v-model,接收"seltipoption"事件等。
編寫
1 新建組件“seltipoption.vue”
該組件需要完成的功能是:顯示標(biāo)簽內(nèi)容、響應(yīng)點(diǎn)擊事件、高亮顯示是否被選中。
<template>
<span class="tip" @click="selectOptionClick" :class="{'active':itemSelected }">{{currentLabel}}</span>
</template>
<script type="text/ecmascript-6">
import Emitter from "../emitter";
var underscore = require("../underscore-min");
export default{
mixins: [Emitter],
componentName: "seltipoption",
props: {
value: {
required: true
},
label: [String, Number],
},
//屬性計(jì)算
computed: {
currentLabel() {
return this.label || ((typeof this.value === 'string' || typeof this.value === 'number') ? this.value : '');
},
parent() {
let result = this.$parent;
while (!result.istipSelect) {
result = result.$parent;
}
return result;
},
itemSelected() {
if (!this.parent.multiple) {
//由于現(xiàn)實(shí)問題,此處underscore..isEqual中間為下劃線_
return underscore._.isEqual( this.parent.value, this.value);
} else {
let isSelected = false;
this.parent.value.forEach((item, index) => {
//由于現(xiàn)實(shí)問題,此處underscore..isEqual中間為下劃線_
if (underscore._.isEqual(item, this.value)) {
isSelected = true;
}
});
return isSelected;
}
},
},
methods: {
selectOptionClick(){
this.dispatch('seltiplist', 'handleOptionClick', this.value);
}
}
}
</script>
2 新建組件 “seltiplist.vue”
該組件需要實(shí)現(xiàn)的功能:子組件內(nèi)容分發(fā)、響應(yīng)子組件“seltipoption”選中和取消選中事件、實(shí)現(xiàn)v-model的數(shù)據(jù)雙向綁定。
<template>
<div>
<slot></slot>
</div>
</template>
<script type="text/ecmascript-6">
import Emitter from "../emitter";
var underscore = require("../underscore-min");
export
default {
mixins:[Emitter],
componentName: "seltiplist",//組件名稱,自定義字段。方便用這個(gè)屬性進(jìn)行組件間交流
data() {
return {
istipSelect: true
}
},
props: {
value: {},
multiple: {
type: Boolean,
default:false
}//屬性標(biāo)識(shí)篩選條件是單選項(xiàng)還是多選項(xiàng)
},
mounted() {
this.$on('handleOptionClick', this.handleOptionSelect);
},
methods: {
handleOptionSelect(val) {
//由于現(xiàn)實(shí)問題,此處underscore..isArray中間為下劃線
if (this.multiple && underscore._.isArray(this.value) ) {
this.value.forEach( (item, index ) => {
//由于現(xiàn)實(shí)問題,此處underscore..isEqual中間為下劃線_
if (underscore._.isEqual(item, val)) {
optionIndex = index;
}
});
if (optionIndex < 0) {
this.value.push(val);
} else {
this.value.splice(optionIndex, 1)
}
} else {
if (val != this.value) {
this.$emit('input', val);
} else {
this.$emit('input', "");
}
}
}
}
}
</script>
</code>
3 組件使用
<div class="selectlist">
<div class="title">地區(qū)</div>
<div class="select-box">
<seltiplist v-model="loacl_select">
<seltipoption v-for=" item in local " :label="item.label" :value="item"></seltipoption>
</seltiplist>
</div>
</div>
<div class="selectlist">
<div class="title">薪資要求</div>
<div class="select-box">
<seltiplist v-model="salary_select">
<seltipoption v-for=" item in salary " :label="item.label" :value="item"></seltipoption>
</seltiplist>
</div>
</div>
<div class="selectlist">
<div class="title">福利待遇</div>
<div class="select-box">
<seltiplist :multiple="true" v-model="treatment_select">
<seltipoption v-for=" item in treatment " :label="item.label" :value="item"></seltipoption>
</seltiplist>
</div>
</div>
<script>
import seltiplist from "./seltiplist.vue";
import seltipoption from "./seltipoption.vue";
export default{
components: {
seltiplist,
seltipoption
},
data(){
return{
loacl_select:"",
treatment_select:[{
id:4,
label:"項(xiàng)目獎(jiǎng)金"
}],
salary_select:"",
local:[{
id:1,
label:"北京"
},{
id:2,
label:"安徽"
},{
id:3,
label:"上海"
},{
id:4,
label:"廣州"
}],
treatment:[{
id:1,
label:"五險(xiǎn)一金"
},{
id:2,
label:"交通補(bǔ)助"
},{
id:3,
label:"帶薪年假"
},{
id:4,
label:"項(xiàng)目獎(jiǎng)金"
}],
salary:[{
id:1,
label:"4000以下"
},{
id:2,
label:"4000-6000"
},{
id:3,
label:"6000-8000"
},{
id:4,
label:"8000以上"
}]
}
},
methods: {}
}
</script>
4 代碼解讀
1,如何實(shí)現(xiàn)的自定義組件v-model數(shù)據(jù)雙向綁定?
如果要讓組件的 v-model 生效,則這個(gè)組件它必須:
- 接受一個(gè) value 屬性
- 在有新的 value 時(shí)觸發(fā) input 事件,直接賦值給
this.value是無效的,無法觸發(fā)更新。 - 當(dāng)為多選項(xiàng)時(shí),更新seltiplist組件的value數(shù)組即可,但是當(dāng)為單選項(xiàng)時(shí),需要使用
this.$emit('input', val);來觸發(fā)更新。
2,父子組件通訊。
我加入了一個(gè)minx混合,也就是組件中看到引入的Emitter
function broadcast(componentName, eventName, params) {
this.$children.forEach(child => {
var name = child.$options.componentName;
if (name === componentName) {
child.$emit.apply(child, [eventName].concat(params));
} else {
broadcast.apply(child, [componentName, eventName].concat(params));
}
});
}
export default {
methods: {
//事件向上傳播,參數(shù):接收事件組件的componentName屬性,事件名稱,傳入的參數(shù)
dispatch(componentName, eventName, params) {
var parent = this.$parent || this.$root;
var name = parent.$options.componentName;
//根據(jù)組件的componentName值,找到父組件
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.componentName;
}
}
///父組件觸發(fā)$emit回調(diào)
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params));
}
},
//事件向下傳播,參數(shù):接收事件組件的componentName屬性,事件名稱,傳入的參數(shù)(原理同上)
broadcast(componentName, eventName, params) {
broadcast.call(this, componentName, eventName, params);
}
}
};
當(dāng) seltipoption.vue 響應(yīng)click事件后,通過this.dispatch('seltiplist', 'handleOptionClick', this.value);
觸發(fā)父組件 seltiplist.vue 的監(jiān)聽this.$on('handleOptionClick', this.handleOptionSelect);實(shí)現(xiàn)組件間的通訊。并且在一定程度上可以起到解耦的作用。
3, seltipoption 的選擇狀態(tài)判斷
當(dāng)為單選項(xiàng)時(shí) ,判斷seltipoption的value是否等于seltiplist的value;
當(dāng)為多選項(xiàng)時(shí),seltipoption的value存在于seltiplist value的數(shù)組中。
為了判斷兩個(gè)value是否值相等。此處引入工具underscore
github:https://github.com/jashkenas/underscore,
文檔:http://underscorejs.org/
總結(jié)
代碼量不多,也沒有對每個(gè)方法進(jìn)行說明,但是非常適合準(zhǔn)備入手自定義組件同行們。提供了一些組件開發(fā)的思路,有很多時(shí)候組件配合使用更為便捷。
demo的代碼已上傳至github,以便參考學(xué)習(xí)。
github:https://github.com/DevilLeven/select_tip