利用vue組件自定義v-model實(shí)現(xiàn)一個(gè)Tab組件方法示例
前言
最近在學(xué)習(xí)vue,今天看到自定義組件,糾結(jié)了一會(huì)會(huì)然后恍然大悟...官方教程寫得不是很詳細(xì),所以我決定總結(jié)一下。下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧。
效果
先讓我們看一下例子的效果吧!

v-model
我們知道 v-model 是 vue 里面的一個(gè)指令,vue的v-model是一個(gè)十分強(qiáng)大的指令,它可以自動(dòng)讓原生表單組件的值自動(dòng)和你選擇的值綁定,它可以用在 input 標(biāo)簽上,來(lái)做數(shù)據(jù)的雙向綁定,就像這樣:
<input v-model="tab">
v-model 事實(shí)上是一個(gè)語(yǔ)法糖,你也可以這么寫:
<input :value="tab" :input="tab = $event.target.value">
可以看得出來(lái),就是傳進(jìn)去一個(gè)參數(shù) :value,監(jiān)聽(tīng)一個(gè)事件 @input 而已。
如果有這樣的需求,需要在自己的組件上使用 v-model,就像這樣:
<Tab v-model="tab"></Tab>
如何來(lái)實(shí)現(xiàn)呢?
既然已經(jīng)知道 v-model 是語(yǔ)法糖了,那么首先,我們可以知道在組件內(nèi)得到的參數(shù)。
<!-- Tab.vue -->
<template>
<div class="tab">
<p>可以試著把這個(gè)值打印出來(lái)😀😀😀</p>
{{value}}
</div>
</template>
<script>
export default {
props: {
// ↓這個(gè)就是我們能取到的參數(shù)
value: {
type: String,
default: ''
}
}
}
</script>
嗯,先把這個(gè) value 先放著,如果要實(shí)現(xiàn)例子的那個(gè) Tab,還需要傳進(jìn)來(lái)一組選項(xiàng)(options):
<!-- example.vue -->
<template>
<div>
<!-- 這里多了一個(gè)參數(shù) ↓ -->
<Tab v-model="tab" :options="options"></Tab>
<p class="info">{{tab}}</p>
</div>
</template>
<script>
import Tab from '~/Tab';
export default {
components: {
Tab
},
data() {
return {
tab: 'bj',
options: [{
value: 'bj',
text: '北京'
}, {
value: 'sh',
text: '上海',
disabled: true
}, {
value: 'gz',
text: '廣州'
}, {
value: 'sz',
text: '深圳'
}]
}
}
}
</script>
那我們就把傳進(jìn)來(lái)的 options 循環(huán)出來(lái)吧!
<!-- Tab.vue -->
<template>
<div class="tab">
<div
class="item"
v-for="(item, i) in options"
:key="i">
{{item.text}}
</div>
</div>
</template>
<script>
export default {
props: {
value: {
type: String
},
options: {
type: Array,
default: []
}
}
}
</script>
傳進(jìn)來(lái)的 options 缺少些參數(shù),我們每個(gè)選項(xiàng)需要 active 來(lái)標(biāo)記是否是選中狀態(tài),需要 disabled 來(lái)標(biāo)記是否是禁選狀態(tài),所以拷貝一個(gè) currOptions 來(lái)補(bǔ)全不足參數(shù)。
另外直接改變 value 這個(gè) props 是沒(méi)有效果滴,所以拷貝一個(gè) value 的副本,叫 currValue。
<!-- Tab.vue -->
<script>
export default {
props: {
value: {
type: String
},
options: {
type: Array,
default: []
}
},
data() {
return {
// 拷貝一個(gè) value
currValue: this.value,
currOptions: []
}
},
mounted() {
this.initOptions();
},
methods: {
initOptions() {
// 拷貝一個(gè) options
this.currOptions = this.options.map(item => {
return {
...item,
active: item.value === this.currValue,
disabled: !!item.disabled
}
});
}
}
}
</script>
🆗接下來(lái)再在選項(xiàng)上綁定擊事件就 OK 了。
既然知道父組件會(huì)接受 input 事件,那我們就只需要 this.$emit('input', this.currValue); 就好了。
<!-- Tab.vue -->
<template>
<div class="tab">
<div
class="item"
v-for="(item, i) in options"
:key="i"
@click="onTabSelect(item)">
<!-- ↑ 這里綁定了一個(gè)事件! -->
{{item.text}}
</div>
</div>
</template>
<script>
export default {
props: {
value: {
type: String
},
options: {
type: Array,
default: []
}
},
data() {
return {
currValue: this.value,
currOptions: []
}
},
mounted() {
this.initOptions();
},
methods: {
initOptions() {
this.currOptions = this.options.map(item => {
return {
...item,
active: item.value === this.currValue,
disabled: !!item.disabled
}
});
},
// 添加選中事件
onTabSelect(item) {
if (item.disabled) return;
this.currOptions.forEach(obj => obj.active = false);
item.active = true;
this.currValue = item.value;
// 發(fā)布 input 事件,↓ 父組件如果有 v-model 就會(huì)監(jiān)聽(tīng)到的。
this.$emit('input', this.currValue);
}
}
}
</script>
剩下的補(bǔ)上點(diǎn)樣式還有 watch 下 value 和 options 的變化就可以了,最后貼上完整代碼。
完整代碼
<!-- example.vue -->
<template>
<div>
<Tab v-model="tab" :options="options"></Tab>
<p class="info">{{tab}}</p>
</div>
</template>
<script>
import Tab from '~/Tab';
export default {
components: {
Tab
},
data() {
return {
tab: 'bj',
options: [{
value: 'bj',
text: '北京'
}, {
value: 'sh',
text: '上海',
disabled: true
}, {
value: 'gz',
text: '廣州'
}, {
value: 'sz',
text: '深圳'
}]
}
}
}
</script>
<style lang="less" scoped>
.info {
margin-left: 50px;
font-size: 30px;
}
</style>
<!-- Tab.vue -->
<template>
<div class="tab">
<div
class="item"
v-for="(item, i) in currOptions"
:class="item | tabItemClass"
:key="i"
@click="onTabSelect(item)">
{{item.text}}
</div>
</div>
</template>
<script>
export default {
props: {
value: {
type: String
},
options: {
type: Array,
default: []
}
},
data() {
return {
currValue: this.value,
currOptions: []
}
},
mounted() {
this.initOptions();
},
methods: {
initOptions() {
this.currOptions = this.options.map(item => {
return {
...item,
active: item.value === this.currValue,
disabled: !!item.disabled
}
});
},
onTabSelect(item) {
if (item.disabled) return;
this.currOptions.forEach(obj => obj.active = false);
item.active = true;
this.currValue = item.value;
this.$emit('input', this.currValue);
}
},
filters: {
tabItemClass(item) {
let classList = [];
if (item.active) classList.push('active');
if (item.disabled) classList.push('disabled');
return classList.join(' ');
}
},
watch: {
options(value) {
this.initOptions();
},
value(value) {
this.currValue = value;
}
}
}
</script>
<style lang="less" scoped>
.tab {
@borderColor: #ddd;
@radius: 5px;
width: 100%;
margin: 50px;
overflow: hidden;
position: relative;
.item {
padding: 10px 50px;
border-top: 1px solid @borderColor;
border-left: 1px solid @borderColor;
border-bottom: 1px solid @borderColor;
font-size: 30px;
background-color: #fff;
float: left;
user-select: none;
cursor: pointer;
transition: 300ms;
&:first-child {
border-top-left-radius: @radius;
border-bottom-left-radius: @radius;
}
&:last-child {
border-right: 1px solid @borderColor;
border-top-right-radius: @radius;
border-bottom-right-radius: @radius;
}
&.active {
color: #fff;
background-color: red;
}
&:hover {
color: #fff;
background-color: #f06;
}
&.disabled {
color: #fff;
background-color: pink;
cursor: no-drop;
}
}
}
</style>
最后送上官網(wǎng)的鏈接→ 傳送門
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
vue中echarts圖表大小適應(yīng)窗口大小且不需要刷新案例
這篇文章主要介紹了vue中echarts圖表大小適應(yīng)窗口大小且不需要刷新案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07
在Vue中實(shí)現(xiàn)二維碼生成與掃描功能的方法
二維碼是一種廣泛應(yīng)用于各種場(chǎng)合的編碼方式,它可以將信息編碼成一張二維圖案,方便快捷地傳遞信息,在Vue.js中,我們可以使用一些庫(kù)和組件來(lái)實(shí)現(xiàn)二維碼的生成和掃描,本文將介紹如何在Vue中實(shí)現(xiàn)二維碼的生成和掃描的方法2023-06-06
vue-router項(xiàng)目實(shí)戰(zhàn)總結(jié)篇
vue-router 是 Vue.js 官方的路由庫(kù).這篇文章主要介紹了vue-router項(xiàng)目實(shí)戰(zhàn)總結(jié),需要的朋友可以參考下2018-02-02
VUE+Canvas實(shí)現(xiàn)簡(jiǎn)單五子棋游戲的全過(guò)程
這篇文章主要給大家介紹了關(guān)于VUE+Canvas實(shí)現(xiàn)簡(jiǎn)單五子棋游戲的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
Vue關(guān)于訪問(wèn)外鏈?zhǔn)〉膯?wèn)題
這篇文章主要介紹了Vue關(guān)于訪問(wèn)外鏈?zhǔn)〉膯?wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03

