Vue.js Компонент с v-моделью

Мне удалось добиться двухуровневого связывания v-модели на одном уровне с пользовательским компонентом, но мне нужно сделать его еще глубже.

Текущий рабочий код:

    <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-модели ваших компонентов, чтобы вы могли передавать значения по дереву, а также создавать резервные копии дерева. Я также добавил наблюдателей к вашим компонентам, так что если вам нужно обновить значение объекта электронной почты вне компонента редактора электронной почты, обновления будут отражены в компоненте.

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>

В приведенном выше примере при вводе значений во входные данные обновляется родительский элемент. Кроме того, я добавил кнопку, которая изменяет значение родительского элемента для имитации изменения значения вне компонента и изменений, отражаемых в компонентах.

Там нет никакой реальной причины для использования ref S вообще для этого кода.

В моем случае не удалось выполнить сквозной перенос вручную для обоих компонентов. Тем не менее, замена моего первого пользовательского компонента следующим образом:

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

Используя только v-модель в первом компоненте и затем позволяя второму пользовательскому компоненту излучать вверх, добились цели.

Другие вопросы по тегам