2017-06-12 50 views
2

我已经能够在自定义组件上完成单层深度的v-模型双向绑定,但需要更深入一层。带v模型的Vue.js组件

当前工作代码:

<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。如何通过所有自定义组件获取这些值,而不管嵌套?

回答

2

我已经更新了一下代码来处理在组件上使用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/[email protected]/dist/vue.js"></script> 
 
<div id="app"> 
 
    <email-editor v-model="email"></email-editor> 
 
    <div> 
 
    {{email}} 
 
    </div> 
 
    <button @click="email={email:'[email protected]', body: 'testing body' }">change</button> 
 
</div>

在上面的例子中,在输入端中输入值来更新父。此外,我添加了一个按钮,用于更改父组件的值,以模拟更改组件以及组件中所反映的更改的值

根本没有真正的理由使用ref s代码。

+0

这些似乎是一个更完整的解决方案。我已经将它添加到我的代码库中,并且它可以工作。只是为了确保我遵循你的逻辑。道具传递给孩子,孩子使用观察者来捕捉父母对道具的任何变化并相应地调整其实例范围变量。实例范围变量data用于输入作为v-model来维护用户编辑的内容,并通过emit on输入传递给父级。这是否涵盖了你的逻辑链? – steventnorris

+0

@steventnorris你明白了。 – Bert

0

在我的情况下,在两个组件上手动完成passthrough不起作用。然而,这种替代我的第一个自定义组件做:

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

使用第一组件只V-模型,然后让第二个自定义组件发出向上的伎俩。