Динамическое изменение данных в экземпляре Vue на основе входного элемента

#javascript #html #vue.js #vuejs2

Вопрос:

Я начинающий с Vue и JS, и я изо всех сил пытаюсь обновить атрибут данных экземпляра Vue на основе пользовательского ввода. Это то, что у меня есть в качестве шаблона для компонента Vue (расположенного внутри taskTemplate переменной):

 <div>
  <input type="text" placeholder="Insert your task" v-model="desc"/>
  <p>{{ desc }}</p>
</div>
 

Компонент Vue определяется следующим образом:

 Vue.component("task-item", {
  props: {
    id: Number,
    desc: String,
  },
  template: taskTemplate
});
 

И это заполняется в HTML следующим образом:

 <div id="task-list">
  <task-item
    v-for="item in taskList"
    v-bind="item"
  ></task-item>
  <div id="add-more">
    <button v-on:click="newTask" type="button">Add a new task</button>
  </div>
</div>
 

Где список задач создается с помощью экземпляра Vue:

 var app = new Vue({
  el: "#task-list",
  data: {
    taskList: [
      { id: 1, desc: "" },
      { id: 2, desc: "" },
    ]
  },
  methods: {
    newTask() {
      this.taskList.push({ id: this.taskList.length   1, desc: "" })
    }
  }
});
 

Моя проблема в том, что после обновления input элемента на веб-странице свойство компонента обновляется, но если я введу его в консоль app.taskList[0].desc , он все равно вернет пустую строку.

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

Комментарии:

1. Вы не должны мутировать реквизит: вы должны были получить предупреждение в консоли вашего браузера. Вместо этого заставьте компонент элемента задачи вносить изменения в родительский элемент, в котором находится источник данных. Смотрите: vuejs.org/v2/guide/components.html#Using-v-model-on-Components

Ответ №1:

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

 <div>
  <input 
     type="text" 
     placeholder="Insert your task" 
     :value="desc"
     @input="$emit('update:desc', $event.target.value)"
  />
  <p>{{ desc }}</p>
</div>
 

В родительском компоненте вам нужно прослушать update событие и обновить исходное значение:

 <div id="task-list">
  <task-item
    v-for="item in taskList"
    :key="item.id" // do not forget about key
    v-bind="item"
    @update:desc="item.desc = $event"
    // or you can use the sync modifier to listen to update events for all item's props.
    // v-bind.sync="item"
  ></task-item>
  <div id="add-more">
    <button v-on:click="newTask" type="button">Add a new task</button>
  </div>
</div>
 

Ответ №2:

Попробуйте использовать :value и @input вместо v-model :

 Vue.component('task-item', {
  template: `
    <div>
      <input type="text" 
             placeholder="Insert your task" 
             :value="desc"
             @input="$emit('update', $event.target.value)"/>
      <p>{{ desc }}</p>
    </div>
  `,
  props: {
    id: Number,
    desc: String,
  },
  //template: taskTemplate
})

new Vue({
  el: '#demo',
  data: {
    taskList: [
      { id: 1, desc: "" },
      { id: 2, desc: "" },
    ]
  },
  methods: {
    newTask() {
      this.taskList.push({ id: this.taskList.length   1, desc: "" })
    }
  }
}) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
  <div id="task-list">
    <task-item
      v-for="(item, index) in taskList"
      :key="index"
      v-bind="item"
      @update="item.desc = $event"
    ></task-item>
    <div id="add-more">
      <button v-on:click="newTask" type="button">Add a new task</button>
    </div>
  </div>
</div>