Vue2 v – in the model

Vue provides us with v-model instructions to implement bi-directional data binding. Bi-directional data binding means that data updates elements and data updates when elements are updated.

Let’s review the usage of Vue2:

<template>
  <div id="app">
    <input type="text" v-model="value">
    <p>{{value}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: ''
    }
  }
}
</script>
Copy the code

V-model is actually a syntactic sugar, essentially written as follows:

<input type="text" :value="value" @input="value=$event.target.value">
Copy the code

Use of forms

In addition to the input element, the other form elements, the V-Model, can be bidirectional data bound, but the data types are different.

Radio buttons

For input:radio, it is the same as input:text, passing a string value, but listening for change and modifying the HTML property checked

<div id="app">
    <label>
        apple <input type="radio" value="apple" v-model="picked">
    </label>
    <label>
        orange <input type="radio" value="orange" v-model="picked">
    </label>
    <label>
        banana <input type="radio" value="banana" v-model="picked">
    </label>
</div>
Copy the code

Check box

Check boxes, like checkboxes, are internally listening for change events. But there are two cases of multiple checkboxes:

We can use a single check box to indicate select/deselect, or multiple check boxes to indicate which to select.

Single check box

Two-way data binding is accomplished by binding the V-Model to a Boolean value.

Multiple check boxes

Bind the V-Models of these check boxes to the same array. The value in the data is the selected value.

<div id="app"> <input type="checkbox" id="1" value="xxx" v-model="checked"> <label for="1">xxx</label> <input type="checkbox" id="2" value="yyy" v-model="checked"> <label for="2">yyy</label> <input type="checkbox" id="3" Value = "z" v - model = "checked" > < label for = "3" > z < / label > < br > < span > selected are: {{checked}} < / span > < / div >Copy the code

Others include select and Textarea. See the official documentation for form input bindings

Use of components

Not only form elements can be used, but components can also implement two-way data binding.

For example, there is a my-input component:

<template>
  <div class="my-input">
    :value="value" @input="$emit('input', $event.target.value)"
    <p>value: {{ value }}</p>
  </div>
</template>

<script>
export default {
    props: ['value']
};
</script>

Copy the code

Then use it in app.vue:

<template> <div id="app"> <my-input v-model="value" /> </div> </template> <script> import MyInput from './components/MyInput' export default { components: { MyInput }, data() { return { value: "", }; }}; </script>Copy the code

Such V-models are still syntactically sugar, essentially doing what they bind to the value property and listen for input events:

<my-input :value="value" @input="value = $event" />
Copy the code

If we want to implement other forms of V-Model, we need to configure an option inside the component:

Prop represents the value of the external property bound when using the V-Model on the component, and Event represents the event to listen for (which can be a custom event)

model: {
    prop: 'checked',
    event: 'change'
},
Copy the code

The sync modifier

However, v-Model for components to achieve two-way data binding has a disadvantage, that is, only one data can be bound, not multiple two-way data binding.

Vue2 provides another way to implement bidirectional data binding, the SYNC modifier of V-bind.

For example, with the my-Input component’s bidirectional data binding, we only need to modify the code a little bit:

// App.vue
<my-input :value.sync="value" />

// MyInput.vue
<input type="text" :value="value" @input="$emit('update:value', $event.target.value)" />
Copy the code

In essence, what.sync does is listen for custom events for the update: bound property. The previous app. vue is equivalent to:

<my-input :value="value" @update:value="value = $event" />
Copy the code

Comparison of the two:

  1. Both are used to implement two-way data transfer, implemented by syntax sugar, and finally passedprop + The eventTo get the job done.
  2. v-modelOnly one two-way data gang binding can be implemented;.syncWhenever two-way data transfer is required, it can be used.

Changes in Vue3

Vue2 is criticized for providing two bidirectional bindings: v-model and.sync. In Vue3, the.sync modifier is removed and only v-model is used for bidirectional binding.

In order to make v-Model better bidirectional binding for multiple attributes, Vue3 made the following changes:

  1. When used with custom componentsv-modelDirective, the default property name of the binding is changed from the originalvalueintomodelValue, the event name is changed from the originalinput intoupdate:modelValue
  2. Remove the.syncModifier, whose original function is defined byv-modelParameter substitution of
  3. modelConfiguration removed
  4. Allow customizationv-modelThe modifier

Note that there is no change in using the V-Model for normal form elements, only two-way data binding for components, which is simply a combination of v-Model and.sync.

If you don’t understand, change the previous example to the version of Vue3:

// app. vue <my-input v-model="value" /> // equivalent to // <my-input V-model :modelValue="value" @update:modelValue="value = $event" /> // MyInput.vue <input type="text" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />Copy the code

One might say what if I need to bind multiple data? Or if I don’t want to use the attribute name modelValue, then according to principle (point 2), use the parameter of V-model:

<my-input v-model:inpVal="value" />

<input type="text" :value="inpVal" @input="$emit('update:inpVal', $event.target.value)" />
Copy the code

Because of the second point, the third point comes naturally, and the Model configuration is no longer required. Fourth, Vue3 can be upgraded with custom attribute modifiers:

Here’s a picture to illustrate: If we use the V-Model attribute modifier, Vue will pass a modelModifiers inside the component in addition to the modelValue attribute, which is an object It contains all the attribute modifiers used by the V-Model.

If the V-Model uses parameters, that is, doesn’t use the default modelValue, another attribute passed about attribute Modifiers is called the parameter +Modifiers

Inside the component we can decide what to do with the xxxModifiers attribute passed in.

Let’s modify the previous example:

App.vue

<div id="app">
    <my-input v-model:inpVal.trim="value" />
</div>
Copy the code

MyInput.vue

<template> <div class="my-input"> <input type="text" :value="inpVal" @input="handelInput" /> <p>value: {{ inpVal }}</p> </div> </template> <script> import { onMounted } from "vue"; export default { props: ["inpVal", "inpValModifiers"], setup(props, ctx) { const printModifiers = () => { console.log(props.inpValModifiers); }; const handelInput = (e) => { ctx.emit("update:inpVal", e.target.value); }; onMounted(printModifiers); return { printModifiers, handelInput }; }}; </script>Copy the code

Using the.trim custom modifier, we want to remove the leading and trailing whitespace:

const handelInput = (e) = > {
    let val = e.target.value;
    if(props.inpValModifiers? .trim) { val = val.trim(); } ctx.emit("update:inpVal", val);
};
Copy the code