The principle of Vue is to pass data down through props and emit events up. It may seem straightforward, but it's crucial to remember when creating custom components.
Starting from Vue 2.2.0, you can utilize v-model with computed properties. This combination results in a simplified, neat, and consistent communication channel between components:
- Any props passed to your component remain reactive without the need for cloning or watch functions to track changes.
- Changes are automatically relayed back to the parent component.
- This setup works seamlessly across multiple levels of components.
A computed property allows you to define separate getter and setter methods. This enables you to redesign the 'Task' component as shown below:
Vue.component('Task', {
template: '#task-template',
props: ['list'],
model: {
prop: 'list',
event: 'listchange'
},
computed: {
listLocal: {
get: function() {
return this.list
},
set: function(value) {
this.$emit('listchange', value)
}
}
}
})
The model property specifies which prop corresponds to v-model and which event will be triggered upon changes. You can then use this component from the parent like so:
<Task v-model="parentList"></Task>
The 'listLocal' computed property offers a simple interface for getting and setting data within the component (similar to a private variable). In the '#task-template', you can display 'listLocal' and it will reactively update based on changes in 'parentList'. You can also modify 'listLocal' by calling the setter (e.g., this.listLocal = newList) which triggers an event emission to the parent component.
This pattern allows you to pass 'listLocal' to a child component of 'Task' using v-model, ensuring that changes made at lower levels cascade up to the top level component.
For instance, suppose we have a separate 'EditTask' component for editing task data. By employing the same v-model and computed properties methodology, we can send 'listLocal' to this component using v-model:
<script type="text/x-template" id="task-template">
<div>
<EditTask v-model="listLocal"></EditTask>
</div>
</script>
If 'EditTask' triggers a change, it will directly call set() on 'listLocal', thereby propagating the event to the top-level component. Similarly, 'EditTask' could further communicate with other child components (e.g., form elements) using v-model.