錢端 P0 學習筆記:基於 vue.js 2.3.x 的偽雙向繫結

畫渣程式猿發表於2018-05-08

因為業務需要,最近不寫 iOS,也不寫 Ruby 了,開始寫錢端。然後…做為一個錢端 P0,表示用了 Electron 和餓了麼大錢端的 Element 庫之後,好像一直都很順利,直到…我碰到了元件間值同步的問題?。

需求是這樣的,我需要點選一個按鈕,然後開啟一個對話方塊用來新建一些東西。 對話方塊的話我當然是用 el-dialog 來做啊,Element!So easy!!!el-dialog 有個叫 :visible.sync 的屬性,用來控制它的顯示和隱藏。

如果我不封裝這個對話方塊,直接放在當前頁面,像下面這樣設定就 OK 了:

<template>
  <el-dialog :visible.sync="visible"></el-dialog>
</template>

<script>
  export default {
    data () {
      return {
        visible: false
      }
    }
  }
</script>
複製程式碼

這樣一來我只需要設定 visible 的值就可以控制 el-dialog 節點 的顯示和隱藏了:

<el-button @click="visible = true"></el-button>
複製程式碼

不過本人是個封裝控?,el-dialog 裡面還有一堆東西呢,直接放在這不能忍,所以我很乾脆的把這個 el-dialog 和它的資料放到另外一個元件(PS:子元件)去了,然後,問題就來了:我的按鈕還在當前元件裡(PS:父元件),上面這行程式碼我控制不了這個 visible 屬性了。What the Fuck!!!我需要學習,然後各種查,問,試,期間曲折的過程我就不說了,直接放最終我個人覺得比較能接受的版本吧:

首先我們先定義子元件:

<template>
  <el-dialog :visible.sync="visible"></el-dialog>
</template>

<script>
  export default {
    props: {
      pvisible: Boolean
    },
    computed: {
      visible: {
        // getter
        get: function () {
          return this.pvisible
        },
        // setter
        set: function (newValue) {
          this.$emit('update:pvisible', newValue)
        }
      }
    }
  }
</script>
複製程式碼

這裡有幾個關鍵點:

  1. 父元件會有一個值和子元件的 pvisible 繫結,然後通過 props 傳遞過來,而且需要指定型別,不指定的話預設是字串型別。
  2. 需要一個 computed 的屬性 visible 來控制 el-dialog 的顯示和隱藏,為什麼是 computed?原因有兩個:
    • get 方法可以直接獲取 pvisible 的值並控制 el-dialog 的顯示和隱藏。

    • 要避免直接操作 props 裡面 pvisible 的值,如果直接操作,就會報下面的 warning:

      Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "pvisible"

      這是時候 set 方法就可以通過 emit 方法修改父元件裡的那個值,然後因為父元件裡的那個值和子元件的 pvisible 是繫結的,從而 pvisible 也會發生變化,這樣就避免了上面的問題。

  3. emit 方法第一個引數中的 update: 是固定的,不能瞎寫,這個和 vue 2.3.x 以後的新增特性有關。另外 pvisible 是父元件中那個值的名字。

然後是父元件:

<template>
  <child-components v-bind:pvisible.sync="pvisible"></child-components>
</template>

<script>
  import ChildComponents from './ChildComponents'
  export default {
    data () {
      return {
        pvisible: false
      }
    },
    components: { ChildComponents }
  }
</script>
複製程式碼

這裡同樣有幾個關鍵點:

  1. 需要一個 pvisible 屬性來繫結子元件裡 propspvisible
  2. v-bind:pvisible.sync="pvisible" 就是剛才說的 vue 2.3.x 以後的新特性,繫結屬性的同時,接收子元件 emit 訊息更新。

現在我們就可以在父元件通過設定 pvisibletrue 來顯示對話方塊,然後在子元件中通過設定 visiblefalse 來隱藏對話方塊了。而且他們的狀態只儲存在父元件的 pvisible 中,兩邊改變的也都是 pvisible 的值,這樣就達到了資料統一,並通過資料的改變驅動頁面變化的效果。

Emmm,這也是為什麼我的文章標題是偽雙向繫結了,因為其實改的值都是一個,繫結是單向的,不過因為一些語法糖,然後看起來像是雙向繫結了 pvisiblevisible 這兩個值。

最後,我的理解很有可能是錯的,所以還請各位錢端大佬多多指正!!!感謝?

相關文章