前言:要實現vue的雙向綁定組件,我們實際上需要清楚v-model指令的實際底層交互實現。v-model實際上包含了默認屬性value和默認事件input的父子組件通信過程。
下方舉例說明了我的一個自定義mySelect的實現過程:
<template>
<div class="select">
<div class="input" @click="collapse=!collapse">
<span v-if="currentValue">{{currentLabel||currentValue}}</span>
<span v-else class="placeholder">{{placeholder}}</span>
<span :class="collapse?'arrow-down':'arrow-up'"></span>
</div>
<div class="option-list" v-show="!collapse">
<div class="option-item" v-for="item in data" :key="item.id" @click="chooseItem(item)">{{item[itemLabel?itemLabel:'name']}}</div>
</div>
</div>
</template>
<script>
export default {
name: "mySelect",
props: [
'value',
'placeholder',
'data',
'itemLabel',
'itemValue'
],
data() {
return {
collapse: true,
currentValue: '',
currentLabel: '',
}
},
watch: {
value: {
immediate: true,
handler(value) {
this.currentValue = value;
this.$emit('input', value);
this.data.forEach(item => {
if (item[this.itemValue ? this.itemValue : 'id'] == value) {
return this.currentLabel = item[this.itemLabel ? this.itemLabel : 'name'];
}
});
}
},
data:{
immediate: true,
handler(arr) {
if(this.value||!this.currentLabel){
arr.forEach(item=>{
if(item[this.itemValue ? this.itemValue : 'id'] == this.value){
this.currentLabel = item[this.itemLabel ? this.itemLabel : 'name'];
return;
}
})
}
}
}
},
methods: {
chooseItem(item) {
if (this.currentValue !== item[this.itemValue ? this.itemValue : 'id']) {
this.$emit('change',item[this.itemValue ? this.itemValue : 'id']);
}
this.currentValue = item[this.itemValue ? this.itemValue : 'id'];
this.currentLabel = item[this.itemLabel ? this.itemLabel : 'name'];
this.$emit('input', this.currentValue);
this.collapse = true;
}
}
}
</script>
<style lang="scss" scoped>
.select {
position: relative;
.input {
width: 100%;
height: 30px;
line-height: 30px;
background-color: #fff;
border: 1px solid #02b4fe;
border-radius: 0 3px 3px 0;
padding-left: 10px;
color: #666;
position: relative;
.placeholder {
color: #aaa;
}
}
.arrow-down {
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 8px solid #02b4fe;
position: absolute;
right: 5px;
top: 10px;
}
.arrow-up {
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 8px solid #02b4fe;
position: absolute;
right: 5px;
top: 10px;
}
.option-list {
max-height: 200px;
overflow-y: scroll;
position: absolute;
top: 2rem;
left: 0;
z-index: 5;
width: 100%;
padding: 0 5px;
font-size: 10px;
color: #aaa;
background-color: #fff;
text-align: left;
box-shadow: 0 0 5px rgba(0, 0, 0, .1);
border: 1px solid rgb(79, 192, 232);
.option-item {
text-align: center;
line-height: 1.5rem;
}
}
}
</style>
如上所示,當聲明了mySelect組件之后,在項目中實際使用時,就可以如下所示直接使用:
<template>
<mySelect v-model="testValue" placeholder="請選擇" :data="testArr" item-label="id"
item-value="name"></mySelect>
</template>
<script>
import mySelect from './mySelect'
export default{
components:{
mySelect
},
data(){
return {
testValue:'',
testArr:[]
}
},
mounted(){
//預置select的下拉選擇基礎數據,數據為對象數組,包含id和name屬性
}
}
</script>
以上就是一個簡單的自定義雙向綁定組件的實現,包括簡單的使用過程。在vue中的自定義組件,關于props的聲明時,還是盡量使用官方建議的對象方式,可以聲明屬性的默認值和數據類型。我這邊偷懶了用的是props的字符串數組簡寫方式,但是這樣的話對使用組件時的錯誤調試不利。所以,盡量不要學我偷懶噢,親~~~