利用vue組件自定義v-model實(shí)現(xiàn)一個(gè)Tab組件方法示例
前言
最近在學(xué)習(xí)vue,今天看到自定義組件,糾結(jié)了一會(huì)會(huì)然后恍然大悟...官方教程寫得不是很詳細(xì),所以我決定總結(jié)一下。下面話不多說了,來一起看看詳細(xì)的介紹吧。
效果
先讓我們看一下例子的效果吧!
v-model
我們知道 v-model 是 vue 里面的一個(gè)指令,vue的v-model是一個(gè)十分強(qiáng)大的指令,它可以自動(dòng)讓原生表單組件的值自動(dòng)和你選擇的值綁定,它可以用在 input 標(biāo)簽上,來做數(shù)據(jù)的雙向綁定,就像這樣:
<input v-model="tab">
v-model 事實(shí)上是一個(gè)語法糖,你也可以這么寫:
<input :value="tab" :input="tab = $event.target.value">
可以看得出來,就是傳進(jìn)去一個(gè)參數(shù) :value,監(jiān)聽一個(gè)事件 @input 而已。
如果有這樣的需求,需要在自己的組件上使用 v-model,就像這樣:
<Tab v-model="tab"></Tab>
如何來實(shí)現(xiàn)呢?
既然已經(jīng)知道 v-model 是語法糖了,那么首先,我們可以知道在組件內(nèi)得到的參數(shù)。
<!-- Tab.vue --> <template> <div class="tab"> <p>可以試著把這個(gè)值打印出來😀😀😀</p> {{value}} </div> </template> <script> export default { props: { // ↓這個(gè)就是我們能取到的參數(shù) value: { type: String, default: '' } } } </script>
嗯,先把這個(gè) value 先放著,如果要實(shí)現(xiàn)例子的那個(gè) Tab,還需要傳進(jìn)來一組選項(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)來的 options 循環(huán)出來吧!
<!-- 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)來的 options 缺少些參數(shù),我們每個(gè)選項(xiàng)需要 active 來標(biāo)記是否是選中狀態(tài),需要 disabled 來標(biāo)記是否是禁選狀態(tài),所以拷貝一個(gè) currOptions 來補(bǔ)全不足參數(shù)。
另外直接改變 value 這個(gè) props 是沒有效果滴,所以拷貝一個(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>
🆗接下來再在選項(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)聽到的。 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é)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
antd?select?多選限制個(gè)數(shù)的實(shí)現(xiàn)代碼
這篇文章主要介紹了antd?select?多選限制個(gè)數(shù),實(shí)現(xiàn)思路和核心代碼都很簡單,其中核心代碼在于disabled,代碼簡單易懂需要的朋友可以參考下2022-11-11vue自定v-model實(shí)現(xiàn)表單數(shù)據(jù)雙向綁定問題
vue.js的一大功能便是實(shí)現(xiàn)數(shù)據(jù)的雙向綁定。這篇文章主要介紹了vue自定v-model實(shí)現(xiàn) 表單數(shù)據(jù)雙向綁定的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09詳解如何解決Vue和vue-template-compiler版本之間的問題
這篇文章主要介紹了詳解如何解決Vue和vue-template-compiler版本之間的問題,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-09-09vue-cli實(shí)現(xiàn)異步請(qǐng)求返回mock模擬數(shù)據(jù)
網(wǎng)上有不少使用mockjs模擬數(shù)據(jù)的文章,但基本都是本地?cái)r截請(qǐng)求返回?cái)?shù)據(jù),本文主要介紹了vue-cli實(shí)現(xiàn)異步請(qǐng)求返回mock模擬數(shù)據(jù),文中根據(jù)實(shí)例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03vue中靜態(tài)文件引用的注意事項(xiàng)及說明
這篇文章主要介紹了vue中靜態(tài)文件引用的注意事項(xiàng)及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04vue中響應(yīng)式布局如何將字體大小改成自適應(yīng)
這篇文章主要介紹了vue中響應(yīng)式布局如何將字體大小改成自適應(yīng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09vue+element實(shí)現(xiàn)頁面頂部tag思路詳解
這篇文章主要介紹了vue+element實(shí)現(xiàn)頁面頂部tag效果,頁面顯示由數(shù)組循環(huán)得出,數(shù)組可存儲(chǔ)在store里,tags數(shù)組里面已經(jīng)有值,由于默認(rèn)是白色,所以頁面上看不出,接下來就是給選中的標(biāo)簽高亮,需要的朋友可以參考下2021-12-12Vue + Element-ui的下拉框el-select獲取額外參數(shù)詳解
這篇文章主要介紹了Vue + Element-ui的下拉框el-select獲取額外參數(shù)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08淺析webpack-bundle-analyzer在vue-cli3中的使用
這篇文章主要介紹了webpack-bundle-analyzer在vue-cli3中的使用,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10基于VUE移動(dòng)音樂WEBAPP跨域請(qǐng)求失敗的解決方法
這篇文章主要介紹了基于VUE移動(dòng)音樂WEBAPP跨域請(qǐng)求失敗的解決方法,需要的朋友可以參考下2018-01-01