钱端 P0 学习笔记:基于 vue.js 2.3.x 的伪双向绑定

1,953 阅读3分钟

因为业务需要,最近不写 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 这两个值。

最后,我的理解很有可能是错的,所以还请各位钱端大佬多多指正!!!感谢🙏