Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.
Hello everyone, I am a bowl week, a front end that does not want to be drunk (inrolled). If I am lucky enough to write an article that you like, I am very lucky
Writing in the front
The V-Model in Vue implements two-way data binding. If you are still in the use level, you are really out. Now take a look at the implementation principle of v-Model and how to use this syntax sugar in real development.
The application principle of V-Model
In Vue, we can use V-bind for one-way data binding, that is, passing data from the parent to the child, but conversely, the child cannot modify the data from the parent. This is called one-way data binding.
The V-Model implements two-way data binding, which is essentially an event mechanism provided through Vue. The child emits an event via $emit() and the parent uses V-on to listen for the event and modify the data.
In Vue, the above processing is reduced to a syntactic sugar, namely:
<input type="text" v-model="name">
Copy the code
It’s essentially
<input type="text" :value="name" @input="name = $event.target.value">
Copy the code
However, since form elements in HTML do not always have value attributes, they do not always trigger input events. Therefore, Vue makes individual adaptations for these elements, such as checkboxes, checkboxes, and pull-down menus. These use the change event and the corresponding properties change.
Just remember that the V-Model inside Vue is the syntactic sugar for event binding and event listening.
Use v-Models in components
We learned about v-Model in Vue earlier, now if we want to implement V-Model in V-Model, we only need to perform data binding in the parent component, trigger events in the child component and modify the corresponding data.
Now let’s simulate two v-Model implementations
Combine Vue syntax
Since we use v-Model in conjunction with Vue’s syntax, the first thing we know is that Vue binds the value attribute and listens for input events by default. So we can combine our code with Vue features in a child component to enable two-way data binding.
First we have a parent component that looks like this:
<template>
<div class="container">
<h4>{{"value: "+ value}}</h4>
<! -- Using components -->
<Parent v-model="value"></Parent>
</div>
</template>
<script>
// Import components
import Parent from './components/index'
export default {
// Register the component
components: {
Parent
},
data () {
return {
value: ' '}}},</script>
<style>
.container {
width: 500px;
margin: 100px auto 0;
}
</style>
Copy the code
Now let’s make our own input box component using the contenteditable property provided with
<template>
<div class="input" contenteditable></div>
</template>
<script>
export default{}</script>
<style>
.input {
box-sizing: border-box;
width: 100%;
height: 40px;
line-height: 40px;
outline: none;
padding: 0 15px;
border: 1px solid #dcdfe6;
border-radius: 4px;
color: # 606266;
background-color: #fff;
transition: border-color 0.2 s cubic-bezier(0.645.0.045.0.355.1);
}
.input:focus {
border-color: lightskyblue;
}
</style>
Copy the code
The running effect is as follows:
Now we can implement bidirectional data binding by modifying the above code:
<template>
<! Listen for the start of the input event -->
<div class="input" contenteditable @input="input"></div>
</template>
<script>
export default {
// 1. Accept the value passed by the parent
props: {
value: {
type: String.default: ' '}},methods: {
// 3. Write an event handler for the input event that triggers execution
input (event) {
// 4. $emit input event with event.target.innerText as argument
this.$emit('input', event.target.innerText)
}
},
}
</script>
Copy the code
The CSS style section does not move
The final running effect is as follows:
We now have the V-Model syntax sugar implemented in a custom component.
Using the Model option
It is not impossible for us to use the above method, but it is obviously not ideal because the field we want to implement the V-Model is not necessarily value, so now we need to implement a v-Model with custom attributes.
Now let’s assume that instead of using the value attribute and input event, we use the String attribute and strChange event.
Let’s introduce a description from the official Vue documentation
Allows a custom component to customize prop and Event when using the V-Model. By default, a V-Model on a component uses value as a prop and input as an event, but some input types such as checkboxes and checkbox buttons may want to use Value Prop for different purposes. Using model options can sidestep the conflicts that arise from these situations.
API — vue.js (vuejs.org)
Now that we know what this option does, let’s rewrite this code:
<template>
<! Listen for the start of the input event -->
<div class="input" contenteditable @input="input"></div>
</template>
<script>
export default {
// 1. Accept the value passed by the parent
props: {
string: {
type: String.default: ' '}},// 2. Configure the Model option
model: {
prop: 'string'.event: 'strChange'
},
methods: {
// 4. Write an event handler for the input event that triggers execution
input (event) {
// 5. $emit strChange event with event.target.innerText as parameter
this.$emit('strChange', event.target.innerText)
}
},
}
Copy the code
Implementing the V-Model with the Model option is done.
Use v-Models in multi-tier components
Sometimes when we are in project development, we may have components nested within components. Suppose we now have a supercomponent, parent, child. We want to implement a V-model to pass the values of the supercomponent to the parent and to the child, with two-way data binding.
Through the above implementation, the implementation scheme is as follows:
Supercomponent code
<template>
<div style="padding-top: 80px">
<h3 style="text-align: center">{{" Value in supercomponent: "+ value}}</h3>
<Parent v-model="value"></Parent>
</div>
</template>
<script>
import Parent from './components/index.vue'
export default {
components: {
Parent
},
data () {
return {
value: ' '}}}</script>
<style>
</style>
Copy the code
The code for the parent component
<template>
<div class="container">
<h4>{{" parent component value: "+ value}}</h4>
<Parent v-model="value"></Parent>
</div>
</template>
<script>
import Parent from './child/index'
export default {
components: {
Parent
},
props: {
value: {
type: String.default: ' '}}},</script>
<style>
.container {
width: 500px;
margin: 50px auto 0;
}
</style>
Copy the code
The code for the child component
<template>
<! Listen for the start of the input event -->
<div class="input" contenteditable @input="input"></div>
</template>
<script>
export default {
// 1. Accept the value passed by the parent
props: {
string: {
type: String.default: ' '}},methods: {
// 3. Write an event handler for the input event that triggers execution
input (event) {
// 4. $emit input event with event.target.innerText as argument
this.$emit('input', event.target.innerText)
}
},
}
</script>
<style>
.input {
box-sizing: border-box;
width: 100%;
height: 40px;
line-height: 40px;
outline: none;
padding: 0 15px;
border: 1px solid #dcdfe6;
border-radius: 4px;
color: # 606266;
background-color: #fff;
transition: border-color 0.2 s cubic-bezier(0.645.0.045.0.355.1);
}
.input:focus {
border-color: lightskyblue;
}
</style>
Copy the code
Now when we enter values in the input field will we implement data binding for the three components? The answer is no. Not only does it not, but it throws an exception, as shown below
The error basically means that we are violating the design principle of Vue and should not change the value of the parent component directly in the child component.
There are many ways to solve this problem, but here is a more general and readable one. It is used to evaluate properties to listen for changes in value and then modify the corresponding value.
Now let’s modify the parent component’s code:
<template>
<div class="container">
<h4>{{" parent component value: "+ value}}</h4>
<! -- Use computed properties as passed properties -->
<Parent v-model="newValue"></Parent>
</div>
</template>
<script>
import Parent from './child/index'
export default {
components: {
Parent
},
props: {
value: {
type: String.default: ' '}},computed: {
// Define a transition computed property
newValue: {
get () {
return this.value
},
set (newVal) {
this.$emit('input', newVal)
}
}
}
}
</script>
<style>
.container {
width: 500px;
margin: 50px auto 0;
}
</style>
Copy the code
The modified code runs as follows:
So far we have implemented using the V-Model in a multi-tier component.
Other details of the V-Model
Data type of v-model
The data type of the V-model in Vue is not just a string, it can be any type supported in JavaScript, as shown in the following code:
Parent component code:
<template>
<div class="container">
<h4 style="text-align: center">{{" total "+ array.length +" person "}}</h4>
<! -- Using components -->
<Parent v-model="array"></Parent>
</div>
</template>
<script>
import Parent from './components/index'
export default {
components: {
Parent
},
data () {
return {
array: [{name: 'Joe'.sex: 'male'.age: '18'}}},}</script>
<style>
.container {
width: 500px;
margin: 100px auto 0;
}
</style>
Copy the code
Here we need to implement bidirectional data binding for array.
Sub-component code:
<template>
<div>
<table>
<tr>
<th>The name</th>
<th>gender</th>
<th>age</th>
</tr>
<tr v-for="(item, index) in array" :key="index">
<td>{{ item.name }}</td>
<td>{{ item.sex }}</td>
<td>{{ item.age }}</td>
</tr>
</table>
<button @click="handleClick">Add a person</button>
</div>
</template>
<script>
export default {
props: {
array: {
type: Array.default: null}},model: {
prop: 'array'.event: 'change'
},
methods: {
handleClick () {
let arr = this.array
arr.push({
name: 'Joe'.sex: 'male'.age: '18'
})
this.$emit('change', arr)
}
},
}
</script>
<style>
/* style omit */
</style>
Copy the code
The code run result is as follows:
As we can see from this demo, v-Model syntactic sugar can be implemented for any data type.
The modifier
Vue provides three modifiers for the V-model directive, as follows:
-
.lazy: listens for change instead of input
-
. Number: Converts the input string into a valid number
-
. Trim: Enter the first and last Spaces
For details, please refer to Vue official website
Write in the last
The above content is only available in Vue2 version.
That’s all about v-Model. Welcome to comment + comment.