3

我已经能够在自定义组件上完成单层深度的 v-model 双向绑定,但需要更深一层。

当前工作代码:

    <template lang="html">

      <div class="email-edit">

        <input ref="email" :value="value.email" @input="updateInput()"/>
<input ref="body" :value="value.body" @input="updateInput()"/>

      </div>

    </template>
    <script type="text/javascript">
      import LineEditor from './LineEditor.vue'
      export default {
        components: {
          LineEditor
        },
        computed: {
        },
        methods: {
          updateInput: function(){
            this.$emit('input',{
              email: this.$refs.email.value,
              body: this.$refs.body.value
            })
          }
        },
        data: function(){
          return {}
        },
        props: {
          value: {
            default: {
              email: "",
              body: ""
            },
            type:Object
          }
        }
      }
    </script>

像这样使用:<email-edit-input v-model="emailModel" />

但是,如果我添加这部分,则该值不再向上传播:

      <div class="email-edit">

        <line-editor ref="email" :title="'Email'" :value="value.email" @input="updateInput()"/>
<input ref="body" :value="value.body" @input="updateInput()"/>

      </div>

    </template>
    <script type="text/javascript">
      import LineEditor from './LineEditor.vue'
      export default {
        components: {
          LineEditor
        },
        computed: {
        },
        methods: {
          updateInput: function(){
            this.$emit('input',{
              email: this.$refs.email.value,
              body: this.$refs.body.value
            })
          }
        },
        data: function(){
          return {}
        },
        props: {
          value: {
            default: {
              email: "",
              body: ""
            },
            type:Object
          }
        }
      }
    </script>

使用第二个自定义组件:

<template lang="html">

  <div class="line-edit">
    <div class="line-edit__title">{{title}}</div>
    <input class="line-edit__input" ref="textInput" type="text" :value="value" @input="updateInput()" />
  </div>

</template>
<script type="text/javascript">
  export default {
    components: {
    },
    computed: {
    },
    methods: {
      updateInput: function(){
        this.$emit('input', this.$refs.textInput.value)
      }
    },
    data: function(){
      return {}
    },
    props: {
      title:{
        default:"",
        type:String
      },
      value: {
        default: "",
        type: String
      }
    }
  }
</script>

第一个代码块只需输入即可正常工作。但是,使用两个自定义组件似乎不会在两个组件中冒泡,只有 LineEditor。无论嵌套如何,如何让这些值通过所有自定义组件冒泡?

4

2 回答 2

6

我已经对您的代码进行了一些更新,以便在组件上使用 v-model 来处理,这样您就可以将值传递到树中并备份树。我还在您的组件中添加了观察者,因此如果您应该从电子邮件编辑器组件外部更新电子邮件对象值,则更新将反映在组件中。

console.clear()

const LineEditor = {
  template:`
    <div class="line-edit">
      <div class="line-edit__title">{{title}}</div>
      <input class="line-edit__input" type="text" v-model="email" @input="$emit('input',email)" />
    </div>
  `,
  watch:{
    value(newValue){
      this.email = newValue
    }
  },
  data: function(){
    return {
      email: this.value
    }
  },
  props: {
    title:{
      default:"",
      type:String
    },
    value: {
      default: "",
      type: String
    }
  }
}

const EmailEditor = {
  components: {
    LineEditor
  },
  template:`
    <div class="email-edit">
      <line-editor :title="'Email'" v-model="email" @input="updateInput"/>
      <input :value="value.body" v-model="body" @input="updateInput"/>
    </div>
  `,
  watch:{
    value(newValue){console.log(newValue)
      this.email = newValue.email
      this.body = newValue.body
    }
  },
  methods: {
    updateInput: function(value){
      this.$emit('input', {
        email: this.email,
        body: this.body
      })
    },
  },
  data: function(){
    return {
      email: this.value.email,
      body: this.value.body
    }
  },
  props: {
    value: {
      default: {
        email: "",
        body: ""
      },
      type: Object
    }
  }
}

new Vue({
  el:"#app",
  data:{
    email: {}
  },
  components:{
    EmailEditor
  }
})
<script src="https://unpkg.com/vue@2.2.6/dist/vue.js"></script>
<div id="app">
  <email-editor v-model="email"></email-editor>
  <div>
    {{email}}
  </div>
  <button @click="email={email:'testing@email', body: 'testing body' }">change</button>
</div>

在上面的示例中,在输入中输入值会更新父级。此外,我添加了一个更改父级值的按钮,以模拟组件外部的值更改以及组件中反映的更改。

这段代码根本没有真正的理由使用refs。

于 2017-06-12T19:33:24.440 回答
0

就我而言,在两个组件上手动完成传递不起作用。但是,用这个替换我的第一个自定义组件:

<line-editor ref="email" :title="'Email'" v-model="value.email"/>
<input ref="body" :value="value.body" @input="updateInput()"/>

在第一个组件中只使用 v-model 然后允许第二个自定义组件向上发射就可以了。

于 2017-06-12T19:20:48.177 回答