1. 程式人生 > >通過v-model‘實現’元件雙向資料繫結

通過v-model‘實現’元件雙向資料繫結

單向資料流

  • 單向資料流是Vue元件一個非常明顯的特徵,不應該在子元件中直接修改props的值
  • 如果傳遞的prop僅僅用作展示,不涉及修改,則在模板中直接使用即可
  • 如果需要對prop的值進行轉化然後展示,則應該使用computed計算屬性
  • 如果prop的值用作初始化,應該定義一個子元件的data屬性並將prop作為其初始值

元件之間的通訊

  • 父子元件的關係可以總結為 prop 向下傳遞,事件event向上傳遞
  • 祖先元件和後代元件(跨多代)的資料傳遞,可以使用provideinject來實現
  • 跨元件或者兄弟元件之間的通訊,可以通過eventBus或者vuex等方式來實現

封裝的元件如何實現v-model的資料雙綁的效果

以下兩種通常是我們的實現方式, 看著就很麻煩

  1. 通過emit將事件派發到父元件,prop將資料傳到子元件

    每個父元件都要實現changeValue方法來接收資料並更新資料

    // 子元件
    <template>
    <div>
    <van-button @click="add" type="default">加一</van-button>
    <div>
        {{countsVal}}
    </div>
    <van-button @click="reduce" type="default">減一</van-button>
    </div>
    </template>

    <script>
        export default {
            props: {
                value: Number
            },
            data () {
                return {
                // props的初始化比data的初始化要靠前
                countsVal: this.value
                }
            },
            methods: {
                add () {
                    this.countsVal++
                    this.$emit('add', this.countsVal)
                },
                reduce() {
                    this.countsVal--
                    this.$emit('reduce', this.countsVal)
                }
            }
        };
    </script>

    // 父元件
    <template>
        <div>
                <counter :value='value' @add='changeValue' @reduce='changeValue'/>
        </div>
    </template>

    <script>
        export default {
            data () {
                return {
                value: 10
                }
            },
            methods: {
                changeValue (data) {
                    this.value = data
                }
            }
        };
    </script>
  1. 將加減執行的回到函式通過父元件傳到子元件中實現改變資料

    每個父元件都要實現addreduce兩個方法

    // 子元件
    <template>
    <div>
    <van-button @click="add" type="default">加一</van-button>
    <div>
        {{countsVal}}
    </div>
    <van-button @click="reduce" type="default">減一</van-button>
    </div>
    </template>

    <script>
    export default {
        props: {
            value: Number,
            add: Function,
            reduce: Function
        }
    };
    </script>
    
    // 父元件
    <template>
    <div>
    <counter :value='value' :add='add' :reduce='reduce'/>
    </div>
    </template>

    <script>
        export default {
            data () {
                return {
                value: 10
                }
            },
            methods: {
                add (data) {
                    this.value++
                },
                reduce (data) {
                    this.value--
                }
            }
        };
    </script>

通過v-model語法糖實現,父子組價的資料雙綁

Vue內建了v-model指令,v-model 是一個語法糖,可以拆解為 props: value 和 events: input。就是說元件只要提供一個名為 value 的 prop,以及名為 input 的自定義事件,滿足這兩個條件,使用者就能在自定義元件上使用 v-model,戳這裡看model配置

// 子元件
  <template>
      <div>
          <van-button @click="changeVal(1)" type="default">加一</van-button>
          <div>
              {{countsVal}}
          </div>
          <van-button @click="changeVal(-1)" type="default">減一</van-button>
      </div>
  </template>

  <script>
  export default {
      props: {
          value: Number
      },
      data () {
          return {
          // props的初始化比data的初始化要靠前
          countsVal: this.value
          }
      },
      methods: {
          changeVal (data) {
          this.countsVal += parseInt(data)
          this.$emit('input', this.countsVal)
          }
      }
  }
  </script>
  // 父元件只需要通過v-model將資料傳進去就好了
  <template>
      <div>
          <counter v-model='counts'/>
      </div>
  </template>

  <script>
      import counter from './base/counter'
      export default {
          components: {
              counter
          },
          data () {
              return {
              counts: 10
              }
          }
      }
  <