1. 程式人生 > 實用技巧 >v-model一些理解

v-model一些理解

用過vue同學,都知道v-model可以實現雙向繫結,方便我們的賦值和獲取。

<input v-model="value"/>

使用v-model可以輕鬆的獲取我們輸入的值。下面我們就來研究下其中的原理:

通常我們寫一個元件,子元件要獲取父元件的值,通過props傳值,父元件要獲取子元件要通過$emit繫結一個方法,通過呼叫這個方法獲取相應的值。

子元件:zInput

<template>
  <input type="text" @input="changValue" />
</template>

<script>
export default {
  props: {
    value: { type: String, default: '' }
  },
  methods: {
    changValue(e) {
      this.$emit('input', e.target.value)
    }
  }
}
</script>

父元件:

<template>
  <div class="test">
    <zInput :value="value" @input="getInput" />
  </div>
</template>
<script>
import zInput from './zInput'
export default {
  components: { zInput },
  data() {
    return {
      value: ''
    }
  },  
  methods: {
    // 獲取子元件的值
    getInput(val) {
      console.log(val)
    }
  }
}
</script>

這是一般的寫法,我們該怎麼用v-model實現資料的雙向繫結呢,首先我們要弄清楚model的原理:

一個元件上的 v-model 預設會利用名為 value 的 prop 和名為 input 的事件

v-model 相當於 :value="value" @input="getInput" 那我我們就可以這樣寫父元件了:

<template>
  <div class="test">
    <zInput v-model="value"/>
  </div>
</template>
<script>
import zInput from './zInput'
export default {
  components: { zInput },
  data() {
    return {
      value: ''
    }
  },  
  watch:{ 
    value(val){
      console.log(val)
    }
  }
}
</script>

現在是不是清晰了很多,v-model就是父元件預設傳一個預設為value的值給子元件,並且預設獲取input事件。如果你理解了就可以動手改造我們的程式碼,就可以解決之前的來回傳值和獲取的煩惱了。

如果你還是覺得這樣滿足不了你的需求,你可以嘗試下自定義v-model:

vue2.2.0+ 新增

一個元件上的 v-model 預設會利用名為 value 的 prop 和名為 input 的事件,但是像單選框、複選框等型別的輸入控制元件可能會將 value attribute 用於不同的目的。model 選項可以用來避免這樣的衝突:

先看下官網的例子:

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})

我們可以自定義prpo傳入的值和$emit的事件,這樣我們可以更加靈活的使用v-model,實現我們的需求。

我們可以用computed中的get和set更好的實現的我們的自定義的雙向繫結,如果不是太瞭解,可以看下:計算屬性 vs 偵聽屬性

下面我們用elment-ui中的單選框舉例:

子元件zRadio

<template>
  <div>
    <el-radio-group v-model="radioValue">
      <el-radio-button label="上海"></el-radio-button>
      <el-radio-button label="北京"></el-radio-button>
      <el-radio-button label="廣州"></el-radio-button>
      <el-radio-button label="深圳"></el-radio-button>
    </el-radio-group>
  </div>
</template>

<script>
export default {
  props: {
    radio: { type: String, default: '' }
  },
  model: {
    props: 'radio',// 自定義傳入的值
    event: 'change'// 自定義我們的事件
  },
  computed: {
    radioValue: {
      get() {
        return this.radio // 接收傳進來的值
      },
      set(value) {
        // 設定radio的值並通過model的change的事件傳出改變的值
        this.$emit('change', value) 
      }
    }
  }
}
</script>

父元件:我們可以直接獲取radio的繫結的值,也可以用chang獲取事件

<template>
  <div class="test">
    <zRadio v-model="value" :radio="value" @change="getValue" />
  </div>
</template>
<script>
import zRadio from './zRadio'
export default {
  components: { zRadio },
  data() {
    return {
      value: ''
    }
  },
  watch: {
    value(val) {
      console.log(val)
    }
  },
  methods: {
    getValue(val) {
      console.log(val)
    }
  }
}
</script>

這樣我們精簡了我們的程式碼,也簡化了我們的複雜的傳值,自己動手改造下自己的程式碼吧。