Vue 2.3组件中的双向绑定

dsl*_*101 5 2-way-object-databinding vue.js vuejs2

我理解.sync在Vue 2.3中返回的修饰符,并将其用于实现"多选"问题和答案的简单子组件.父组件像这样调用子组件:

<question
  :stem="What is your favourite colour?"
  :options="['Blue', 'No, wait, aaaaargh!']
  :answer.sync="userChoice"
>
Run Code Online (Sandbox Code Playgroud)

父项具有一个字符串数据元素,userChoice用于存储子组件的结果.孩子为选项提供问题和单选按钮.孩子的基本部分看起来像这样(我使用的是Quasar q-radio):

<template>
  <div>
    <h5>{{stem}}</h5>
    <div class="option" v-for="opt in options">
      <label >
        <q-radio v-model="option" :val="opt.val" @input="handleInput"></q-radio>
        {{opt.text}}
      </label>
    </div>
  </div>
</template>

export default {
  props: {
    stem: String,
    options: Array,
    answer: String
  },
  data: () => ({
    option: null
  }),
  methods: {
    handleInput () {
      this.$emit('update:answer', this.option)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这一切都很好,除了如果父母然后更改userChoice由于应用程序中发生的其他事情的值,孩子不会更新单选按钮.我不得不把这个包含watch在孩子身上:

  watch: {
    answer () {
      this.option = this.answer
    }
  }
Run Code Online (Sandbox Code Playgroud)

但感觉有点多余,我担心发布事件以更新父母的数据实际上会导致孩子'观察'事件也被激活.在这种情况下除了浪费几个周期之外它没有任何效果,但如果它记录或计算任何东西,那将是一个误报...

也许这是真正的双向绑定的正确解决方案(即动态父→子,以及子→父).我是否错过了如何连接双方的'in'和'out'数据?

如果你想知道,想要改变'userChoice'的父母最常见的情况是响应一个'Clear Answers'按钮,它会设置userChoice回一个空字符串.这应该具有'取消'所有单选按钮的效果.

Roy*_*y J 3

您的构造有一些不起作用的奇怪之处,但answer.sync如果您将其传播到q-radio发生更改的组件,则基本上可以工作。更改父级中的答案可以正确处理,但要清除值,似乎您需要将其设置为对象而不是 null (我认为这是因为它需要可分配)。

更新 您的设置options是一个值得注意的事情,但不起作用。

我使用answerq-radio控制其检查状态(v-model在收音机中有特殊行为,这就是我value与 结合使用的原因v-model)。从您的评论来看,似乎q-radio想要有一个可以设置的值。您应该能够使用基于 的计算来做到这一点answer,您可以使用它来代替option数据项:getreturns answer,并且set执行emit。我已经更新了我的代码片段以使用valprop forq-radio加上我描述的计算结果。发出proxyAnswer一个update事件,这正是.sync修饰符想要的。我还q-radio使用计算的代理来实现,但这只是为了获得应该已经烘焙到您的q-radio.

(我所描述的实际上是您对数据项和观察者所做的事情,但计算是封装它的更好方法)。

new Vue({
  el: '#app',
  data: {
    userChoice: null,
    options: ['Blue', 'No, wait, aaaaargh!'].map(v => ({
      value: v,
      text: v
    }))
  },
  components: {
    question: {
      props: {
        stem: String,
        options: Array,
        answer: String
      },
      computed: {
        proxyAnswer: {
          get() {
            return this.answer;
          },
          set(newValue) {
            this.$emit('update:answer', newValue);
          }
        }
      },
      components: {
        qRadio: {
          props: ['value', 'val'],
          computed: {
            proxyValue: {
              get() {
                return this.value;
              },
              set(newValue) {
                this.$emit('input', newValue);
              }
            }
          }
        }
      }
    }
  },
  methods: {
    clearSelection() {
      this.userChoice = {};
    }
  }
});
Run Code Online (Sandbox Code Playgroud)
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<div id="app">
  <question stem="What is your favourite colour?" :options="options" :answer.sync="userChoice" inline-template>
    <div>
      <h5>{{stem}}</h5>
      <div class="option" v-for="opt in options">
        <div>Answer={{answer && answer.text}}, option={{opt.text}}</div>
        <label>
        <q-radio :val="opt" v-model="proxyAnswer" inline-template>
          <input type="radio" :value="val" v-model="proxyValue">
        </q-radio>
        {{opt.text}}
      </label>
      </div>
    </div>
  </question>
  <button @click="clearSelection">Clear</button>
</div>
Run Code Online (Sandbox Code Playgroud)