国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

利用vue組件自定義v-model實現(xiàn)一個Tab組件方法示例

2019-11-19 14:46:47
字體:
供稿:網(wǎng)友

前言

最近在學(xué)習(xí)vue,今天看到自定義組件,糾結(jié)了一會會然后恍然大悟...官方教程寫得不是很詳細,所以我決定總結(jié)一下。下面話不多說了,來一起看看詳細的介紹吧。

效果

先讓我們看一下例子的效果吧!


v-model

我們知道 v-model 是 vue 里面的一個指令,vue的v-model是一個十分強大的指令,它可以自動讓原生表單組件的值自動和你選擇的值綁定,它可以用在 input 標(biāo)簽上,來做數(shù)據(jù)的雙向綁定,就像這樣:

<input v-model="tab">

v-model 事實上是一個語法糖,你也可以這么寫:

<input :value="tab" :input="tab = $event.target.value">

可以看得出來,就是傳進去一個參數(shù) :value,監(jiān)聽一個事件 @input 而已。

如果有這樣的需求,需要在自己的組件上使用 v-model,就像這樣:

<Tab v-model="tab"></Tab>

如何來實現(xiàn)呢?

既然已經(jīng)知道 v-model 是語法糖了,那么首先,我們可以知道在組件內(nèi)得到的參數(shù)。

<!-- Tab.vue --><template> <div class="tab">  <p>可以試著把這個值打印出來😀😀😀</p>  {{value}} </div></template><script> export default {  props: {   // ↓這個就是我們能取到的參數(shù)   value: {    type: String,    default: ''   }  } }</script>

嗯,先把這個 value 先放著,如果要實現(xiàn)例子的那個 Tab,還需要傳進來一組選項(options):

<!-- example.vue --><template> <div>  <!-- 這里多了一個參數(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>

那我們就把傳進來的 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>

傳進來的 options 缺少些參數(shù),我們每個選項需要 active 來標(biāo)記是否是選中狀態(tài),需要 disabled 來標(biāo)記是否是禁選狀態(tài),所以拷貝一個 currOptions 來補全不足參數(shù)。

另外直接改變 value 這個 props 是沒有效果滴,所以拷貝一個 value 的副本,叫 currValue。

<!-- Tab.vue --><script> export default {  props: {   value: {    type: String   },   options: {    type: Array,    default: []   }  },  data() {   return {    // 拷貝一個 value    currValue: this.value,    currOptions: []   }  },  mounted() {   this.initOptions();  },  methods: {   initOptions() {    // 拷貝一個 options    this.currOptions = this.options.map(item => {     return {      ...item,      active: item.value === this.currValue,      disabled: !!item.disabled     }    });   }  } }</script>

🆗接下來再在選項上綁定擊事件就 OK 了。

既然知道父組件會接受 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)">   <!-- ↑ 這里綁定了一個事件! -->   {{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 就會監(jiān)聽到的。    this.$emit('input', this.currValue);   }  } }</script>

剩下的補上點樣式還有 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)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對武林網(wǎng)的支持。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 蒙山县| 宕昌县| 那坡县| 名山县| 加查县| 昆山市| 石泉县| 新巴尔虎左旗| 鄂托克旗| 纳雍县| 郁南县| 徐闻县| 内黄县| 宜丰县| 额济纳旗| 昌吉市| 卓资县| 大姚县| 进贤县| 绥德县| 阜新市| 安达市| 罗江县| 东方市| 襄汾县| 平和县| 蓬莱市| 绥化市| 开封市| 泗洪县| 长海县| 贵阳市| 乐都县| 灵石县| 张北县| 塔河县| 桐乡市| 凤阳县| 洪洞县| 遂昌县| 吴川市|