1. 程式人生 > 其它 >vue 2 實現自定義元件一到多個v-model雙向資料繫結的方法

vue 2 實現自定義元件一到多個v-model雙向資料繫結的方法

前言
有時候我們需要對一個元件繫結自定義 v-model,以更方便地實現雙向資料,例如自定義表單輸入控制元件。

甚至有時候,我們想要實現繫結多個 “v-model”,也就是多個“雙向繫結”,例如帶表單輸入的模組框,想同時控制模態框的顯示狀態與表單的輸入狀態。好在 vue 3 已經實現了多 v-model,那麼在 vue 2 上我們可以如下實現。

1.單個“雙向繫結”的實現
使用 model 實現

其實 v-model 只是 value + change 的語法糖,監聽輸入並觸發改變,因此只要實現 “監聽” + “觸發” 就可以自定義 v-model 啦。

<!-- 父元件 -->
<template>
    <Child v-model="
value" /> </template> <script> export default { data() { return { value: '' } } } </script> <!-- 子元件 --> <template> <input v-model="input" /> </template> <script> export default { props: { value: String, }, model: { prop:
'value', // 指定 v-model 要繫結的引數叫什麼名字,來自於 props 中定義的引數 event: 'change', // 指定要觸發的事件名字,將被用於 $emit }, computed: { input: { // 這裡的計算屬性使用了 getter、setter,可以簡化程式碼 // 可參見連結 https://cn.vuejs.org/v2/guide/computed.html#%E8%AE%A1%E7%AE%97%E5%B1%9E%E6%80%A7%E7%9A%84-setter get() {
return this.value; }, set(val) { this.$emit('change', val); // 觸發 } } } } </script>

這樣一來,就實現了自定義元件的 v-model 實現,重點在於子元件中 model 的宣告和 emit 事件。

2.使用 .sync 實現

除了上面 model 的方法,其實還可以通過 sync 來實現。同樣也是處理“監聽”和“觸發”就行。

在官方文件中有寫,https://cn.vuejs.org/v2/guide/components-custom-events.html#sync-修飾符

用上面相似的例子,可以這樣來實現:

<!-- 父元件 -->
<template>
    <Child :value.sync="value" />
</template>
<script>
export default {
  data() {
    return {
      value: ''
    }
  }
}
</script>

<!-- 子元件 Child -->
<template>
    <input v-model="input" />
</template>
<script>
export default {
  props: {
    value: String,
  },
  computed: {
    input: {
      get() {
        return this.value;
      },
      set(val) {
        this.$emit('update:value', val);    // 這裡的事件名字一定是 'update:' + prop的名字
      }
    }
  }
}
</script>

很顯然,使用這種方法的程式碼量比第1種要少,因為不用寫 model 屬性。只是比起 v-model,v-bind:value.sync 的寫法還是不那麼“引人注目”

多個“雙向繫結”的實現
在 vue 3 出來之前,我們知道在一個標籤裡面最多隻能有一個 v-model。但這並不意味著一個元件只能一次雙向資料繫結。

根據上面 .sync 的方法,我們可以舉一反三,多幾個 update:xxxx 就可以了。

1.分開繫結

下面以一個帶輸入框的模態框為例子,需求是父元件能夠開啟模態框,子元件在輸入確認後能夠關閉模態框;子元件能夠輸入,確認後能夠將值傳給父元件。

<!-- 父元件 -->
<template>
  <!-- 定義了兩個v-bind:xxx.sync來實現兩個雙向繫結 -->
  <ModalInput :value.sync="value" :show.sync="show" />
</template>
<script>
export default {
  data() {
    return {
      value: '',
      show: false
    }
  }
}
</script>

<!-- 子元件 ModalInput -->
<template>
  <!-- 這裡假設Modal是一個帶“確認”按鈕,點選觸發confirm事件,並利用v-model來控制展示的模態框 -->
  <Modal v-model="showModal" @confirm="onConfirm">
    <input v-model="input">
  </Modal>
</template>
<script>
export default {
  props: {
    value: String,
    show: Boolean,
  },
  data() {
    return {
      input: ''        // 在這個例子中,使用 data 來宣告 input,
                  // 因為只有在點選了“確認”按鈕後,才要把值傳給父元件(而不是實時傳)
    }
  },
  computed: {
    showModal: {
      get() {
        return this.show;
      },
      set(val) {
        this.$emit('update:show', val);
      }
    }
  },
  methods: {
    onConfirm() {
      this.$emit('update:value', this.input);
      this.showModal = false
    }
  }
}
</script>

2.合併繫結

上面是綁定了兩個獨立變數的雙向繫結,按照官方的文件,我們甚至還可以用 v-bind.sync 來繫結整個物件(的所有成員!)。下面假設一個表單元件,同時收集個人多個資訊

<!-- 父元件 -->
<template>
  <UserInfoForm v-bind.sync="inputs" />
</template>
<script>
export default {
  data() {
    return {
      inputs: {
        name: '',
        age: 0,
        addr: '',
        phone: ''
      }
    }
  }
}
</script>

<!-- 子元件 UserInfoForm -->
<template>
  <form>
    <input v-model="name">
    <input v-model.number="age">
    <input v-model="addr">
    <input v-model="phone">
  </form>
</template>
<script>
// 與上面例子實現方式相似,這裡省略程式碼若干行。。。
// 其實就是宣告入參 props 有哪些
// 用 computed 來宣告各個變數的 getter 和 setter
// getter 返回傳進來的 prop,setter 中觸發 update:xxxx 事件
</script>

————————————————
版權宣告:本文為CSDN博主「Dobility」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/Dobility/article/details/110147985