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

and HTML, which looks like this:
<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.