[英]Updating an input's bound value when edited
I'm working on a basic to-do application.我正在开发一个基本的待办事项应用程序。 Each to-do/task item gets listed as an input item in a Vue
<list-item>
component, and the <list-item>
s are displayed with a v-for pointing to a tasks array.每个待办事项/任务项都被列为 Vue
<list-item>
组件中的输入项,并且<list-item>
显示为带有指向任务数组的 v-for。
I'm trying to allow the user to edit each task input, and upon changing the value, have this update the array item (rather than just the input itself).我试图让用户编辑每个任务输入,并在更改值后,更新数组项(而不仅仅是输入本身)。 My @change event on the input is firing, but I'm at a loss as to what to do after this point.
我在输入上的@change 事件正在触发,但我不知道在此之后该怎么做。
https://jsfiddle.net/xbxm7hph/ https://jsfiddle.net/xbxm7hph/
HTML: HTML:
<div class="app">
<div class="add-control-area columns is-mobile is-multiline">
<responsive-container>
<div class="field is-grouped">
<div class="control is-expanded">
<input class="input add-control-text" type="text" placeholder="New Task" v-model="newTask" v-on:keyup.enter="addTask">
</div>
<div class="control">
<a class="button is-white add-control-button" @click="addTask" :disabled="!isThereText">Add Task</a>
</div>
</div>
</responsive-container>
<responsive-container>
<list-item v-for="task, index in tasks" :item="task" :index="index" @task-completed="completeTask(index)" @task-deleted="deleteTask(index)" ></list-item>
</responsive-container>
</div>
</div>
JS: JS:
Vue.component('list-item', {
props: ['item', 'index'],
template: `<div class="task-wrapper">
<input class="task" :value="item" @change="updateTask()">
<div class="task-control delete-task" @click="deleteTask()"></div>
<div class="task-control complete-task" @click="completeTask()"></div>
</div>
`,
methods: {
completeTask: function() {
this.$emit('task-completed', this.index);
},
deleteTask: function() {
this.$emit('task-deleted', this.index);
},
updateTask: function() {
console.log('changed');
}
}
});
Vue.component('responsive-container', {
template: `
<div class="column is-4-desktop is-offset-4-desktop is-10-tablet is-offset-1-tablet is-10-mobile is-offset-1-mobile">
<div class="columns is-mobile">
<div class="column is-12">
<slot></slot>
</div>
</div>
</div>
`
});
var app = new Vue({
el: '.app',
data: {
tasks: [],
completedTasks: [],
newTask: ''
},
methods: {
addTask: function() {
if(this.isThereText) {
this.tasks.push(this.newTask);
this.newTask = '';
this.updateStorage();
}
},
completeTask: function(index) {
this.completedTasks.push(this.tasks[index]);
this.tasks.splice(index, 1);
this.updateStorage();
},
deleteTask: function(index) {
this.tasks.splice(index, 1);
this.updateStorage();
},
updateStorage: function() {
localStorage.setItem("tasks", JSON.stringify(this.tasks));
}
},
computed: {
isThereText: function() {
return this.newTask.trim().length;
}
},
// If there's already tasks stored in localStorage,
// populate the tasks array
mounted: function() {
if (localStorage.getItem("tasks")) {
this.tasks = JSON.parse(localStorage.getItem("tasks"));
}
}
});
Use a v-model
directive on your <list-item>
component, instead of passing in an item
property.在
<list-item>
组件上使用v-model
指令,而不是传入item
属性。 You will also need to pass in a reference from the array ( tasks[index]
), because task
in this scope is a copy that is not bound to the element of the array:您还需要从数组 (
tasks[index]
) 中传递一个引用,因为此范围内的task
是未绑定到数组元素的副本:
<list-item v-for="task, index in tasks" v-model="tasks[index]"></list-item>
In your component definition for the list item, you'll need to now take in a value
prop (this is what gets passed when using v-model
) and set a data property item
to that value.在列表项的组件定义中,您现在需要接受一个
value
属性(这是使用v-model
时传递的内容)并将数据属性item
设置为该值。 Then, emit an input
event on the change to pass the item
value (this is what the component is listening for when using v-model
):然后,在更改时发出
input
事件以传递item
值(这是组件在使用v-model
时正在侦听的内容):
Vue.component('list-item', {
props: ['value'],
template: `<div class="task-wrapper">
<input class="task" v-model="item" @change="updateTask"></div>
</div>
`,
data() {
return {
item: this.value,
}
},
methods: {
updateTask: function() {
this.$emit('input', this.item);
}
}
});
Here's a fiddle with those changes.这是这些变化的一个小技巧。
As Bert Evans mentioned, even though this works, Vue requires that components using the v-for
directive also use a key
attribute (you will get a warning from Vue otherwise):正如 Bert Evans 所提到的,即使这有效,Vue 要求使用
v-for
指令的组件也使用key
属性(否则你会收到来自 Vue 的警告):
<list-item v-for="task, index in tasks" :key="index" v-model="tasks[index]" ></list-item>
Also, realize that the index
variable in a v-for
scope can change, meaning that the item at index 1 might change to index 4 and this can pose some problems as the application gets more complex.此外,要意识到
v-for
范围内的index
变量可以更改,这意味着索引 1 处的项目可能会更改为索引 4,这可能会随着应用程序变得更加复杂而带来一些问题。 A better way would be to store items
as an object with an id
property.更好的方法是将
items
存储为具有id
属性的对象。 This way you can have an immutable id associated with the item.这样,您就可以拥有与该项目关联的不可变 id。
You can pass the index and new value to your change event handler:您可以将索引和新值传递给您的更改事件处理程序:
<input class="task" :value="item" @change="updateTask(index, $event)">
Then access them accordingly:然后相应地访问它们:
updateTask: function(index, event) {
console.log(index);
console.log(event.target.value);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.