SoFunction
Updated on 2025-04-07

The principle and usage of Vue are revealed

This article describes the principles and usage of Vue's two-way binding. Share it for your reference, as follows:

When you need to enter what content in Vue, you will naturally think of using it.<input v-model="xxx" />to achieve two-way binding. Here is the simplest example

<div >
  <h2>What's your name:</h2>
  <input v-model="name" />
  <div>Hello {{ name }}</div>
</div>
new Vue({
  el: "#app",
  data: {
      name: ""
  }
});

The contents entered in the input box of this example will be presented later. This is a Vue native pair<input>Good support is also a typical example of two-way data transfer between parent and child components. butv-modelIt is a new feature added to Vue 2.2.0. Before that, Vue only supported one-way data streams.

Vue's one-way data stream

Vue's one-way data flow is similar to React. The parent component can pass data to the child component by setting the properties (Props) of the child component. If the parent component wants to obtain the data of the child component, it must register an event with the child component. This event is triggered when the child component is happy to pass the data. To sum up, Props passes data downwards and events pass data upwards.

The above example, if not usedv-model, it should be like this

<input :value="name" @input="name = $" />

Since event processing is written inline mode, the script part does not need to be modified. But in most cases, events are generally defined as one method, and the code will be much more complex

<input :value="name" @input="updateName" />
new Vue({
  // ....
  methods: {
    updateName(e) {
       = ;
    }
  }
})

From the above examplev-modelSave a lot of code, the most important thing is to define one less event handling function. sov-modelActual events include

  • usev-bind(Right now:) One-way binding of a property (example::value="name"
  • BindinputEvents (i.e.@input) to a default implementation of event handler function (example:@input=updateName
  • This default event handler will modify the bound data based on the value brought in by the event object (example: =

Custom component v-model

Vue encapsulates native components, so<input>It will trigger when inputinputevent. But what should custom components be? Here you might as well use the Todo List example of JsFiddle Vue boilerplate.

Vue boilerplate for JsFiddle

Click the logo of JsFilddle and select the Vue template in the pop-up panel above.

The boilerplate code contains two parts: HTML and Vue(js), and the code is as follows:

<div >
 <h2>Todos:</h2>
 <ol>
  <li v-for="todo in todos">
   <label>
    <input type="checkbox"
     v-on:change="toggle(todo)"
     v-bind:checked="">

    <del v-if="">
     {{  }}
    </del>
    <span v-else>
     {{  }}
    </span>
   </label>
  </li>
 </ol>
</div>
new Vue({
 el: "#app",
 data: {
  todos: [
   { text: "Learn JavaScript", done: false },
   { text: "Learn Vue", done: false },
   { text: "Play around in JSFiddle", done: true },
   { text: "Build something awesome", done: true }
  ]
 },
 methods: {
   toggle: function(todo){
     = !
  }
 }
})

Define Todo components

JsFiddle's Vue template implements the display of a Todo list by default. The data is fixed and all content is completed in one template. The first thing we have to do is to change a single Todo into a child component. Because it cannot be written in JsFiddle as a multi-file form, the component uses()Defining in scripts is mainly to<li>The part of the content is taken out:

("todo", {
  template: `
<label>
  <input type="checkbox" @change="toggle" :checked="isDone">
  <del v-if="isDone">
    {{ text }}
  </del>
  <span v-else>
    {{ text }}
  </span>
</label>
`,
  props: ["text", "done"],
  data() {
    return {
      isDone: 
    };
  },
  methods: {
    toggle() {
       = !;
    }
  }
});

Originally defined in the Apptoggle()The method has also been slightly changed and defined within the component.toggle()When calling, it will modify whether it is completed.donevalue. But becausedoneIt is defined inpropsThe attributes in the file cannot be assigned directly, so the first method recommended by the official is adopted to define a dataisDone, initialized toand use it within the componentisDoneto control whether this state is completed.

The templates and codes of the corresponding App parts have been reduced a lot:

<div >
  <h2>Todos:</h2>
  <ol>
    <li v-for="todo in todos">
      <todo :text="" :done=""></todo>
    </li>
  </ol>
</div>
new Vue({
  el: "#app",
  data: {
    todos: [
      { text: "Learn JavaScript", done: false },
      { text: "Learn Vue", done: false },
      { text: "Play around in JSFiddle", done: true },
      { text: "Build something awesome", done: true }
    ]
  }
});

But up to this point, the data is still one-way. From the perspective of effect, clicking the check box can feedback the deleted line effect, but these dynamic changes aretodoCompleted internally by the component, there is no problem of data binding.

Add a count for Todo List

To maketodoThe state changes inside the component can be presented in the Todo List. We add counts to the Todo List to show the number of Todos that have been completed. Because this quantity istodoThe influence of the internal state of the component (data) requirestodoInternal data changes are reflected into its parent component, which is whatv-modelwhere it works.

This quantity we have in the titlen/mForm presentation, such as2/4It means there are 4 Todos in total and 2 have been completed. This requires modification to the template and code parts of Todo List and addingcountDoneandcountTwo computed properties:

<div >
  <h2>Todos ({{ countDone }}/{{ count }}):</h2>
  <!-- ... -->
</div>
new Vue({
  // ...
  computed: {
    count() {
      return ;
    },
    countDone() {
      return (todo => ).length;
    }
  }
});

The count is now presented, but changing the task state now will not have an impact on this count. We want to make changes in child components affect the data of parent components.v-modelLet’s talk about it later, use the most common method first, event:

  • Subcomponentstodoexisttoggle()TriggeredtoggleEvents andisDoneAs event parameter
  • Parent component is child componenttoggleEvent definition event handling function
("todo", {
  //...
  methods: {
    toggle(e) {
       = !;
      this.$emit("toggle", );
    }
  }
});
&lt;!-- Other codes in #app -->&lt;todo :text="" :done="" @toggle=" = $event"&gt;&lt;/todo&gt;

Here is@toggleThe bound is an expression. Because heretodois a temporary variable, ifmethodsIt is difficult to bind this temporary variable to define a special event handler function (of course, it is possible to define ordinary methods through call forms).

Event handling functions generally correspond directly to the things to be processed, such as definitiononToggle(e), bound to@toggle="onToggle". In this case, it cannot be transmittedtodoAs a parameter.

Ordinary method can be defined astoggle(todo, e), in the event definition, in the form of a function call expression:@toggle="toggle(todo, $event)". It and= $event` same-genuity expression.

Note the difference between the two. The former is a bound processing function (reference), and the latter is a bound expression (reference)

Now the expected results have been achieved through events

Transformed into v-model

We said we should use it beforev-modelImplemented, let’s revamp it now. Pay attention to implementationv-modelSeveral elements of

  • Subcomponents passvalueProperties (Prop) accept input
  • Subcomponent triggersinputEvent output with array parameters
  • Used in parent componentv-modelBind
("todo", {
  // ...
  props: ["text", "value"],  // <-- Note that done has been changed to value  data() {
    return {
      isDone:   // <-- Note It has been changed to    };
  },
  methods: {
    toggle(e) {
       = !;
      this.$emit("input", ); // <-- Note that the event name has changed    }
  }
});
&lt;!-- Other codes in #app -->&lt;todo :text="" v-model=""&gt;&lt;/todo&gt;

.sync implements other data binding

The introduction of Vue 2.2.0 was mentioned earlierv-modelcharacteristic. For some reason, its input properties arevalue, but the output event is calledinputv-modelvalueinputThese three names are literally inconsistent. Although this seems a bit weird, this is not the point. Is the point that a control can only bind one property in two directions?

Vue 2.3.0 has been introduced.syncModifications are used to modifyv-bind(Right now:), making it a two-way binding. This is also syntactic sugar, added.syncThe modified data binding will look likev-modelAlso, the event handling function is automatically registered to assign values ​​to the bound data. This approach also requires that the subcomponent trigger a specific event. However, the name of this event is somewhat related to the binding attribute name, and it is added before the binding attribute nameupdate:Prefix.

for example<sub :="any" />Put the child component'ssomeProperties and parent componentanyData binding is required to pass in subcomponents$emit("update:some", value)to trigger the change.

In the above example, usev-modelThe binding always feels a bit awkward becausev-modelThe literal meaning of this is to bind a numeric value in two directions, indicating whether it is not completeddoneIt is actually a state, not a value. So we modify it again and still usedoneThis property name (notvalue),pass.syncto achieve two-way binding.

("todo", {
  // ...
  props: ["text", "done"],  // <-- Restore to done  data() {
    return {
      isDone:   // <-- Restore to done    };
  },
  methods: {
    toggle(e) {
       = !;
      this.$emit("update:done", ); // <-- Event name: update:done    }
  }
});
&lt;!-- Other codes in #app -->&lt;!-- Notice v-model Become :,Don't forget the colon --&gt;
&lt;todo :text="" :=""&gt;&lt;/todo&gt;

Revealing Vue two-way binding

Through the above description, I think everyone should have understood that Vue's two-way binding is actually done by ordinary one-way binding and event combination, but throughv-modeland.syncThe default processing function is registered to update the data. There is such a paragraph in the Vue source code

// @file: src/compiler/parser/

if () {
  addHandler(
    el,
    `update:${camelize(name)}`,
    genAssignmentCode(value, `$event`)
  )
}

As can be seen from this code,.syncWhen binding on two-way, the compiler will add aupdate:${camelize(name)}event handler function to assign data (genAssignmentCodeliterally means code that generates assignments).

Outlook

Currently, Vue's two-way binding also needs to trigger events to realize data backhaul. This is still a certain difference from many expected assignment back passes. There are two main reasons for this gap

  1. Need to return data through events
  2. Properties (prop) cannot be assigned

In the current version of Vue, simplification can be achieved by defining computed properties, such as

computed: {
  isDone: {
    get() {
      return ;
    },
    set(value) {
      this.$emit("update:done", value);
    }
  }
}

To be honest, it is quite brain-consuming to define more variable names with the same meaning and different names. Hopefully, Vue can reduce this process through certain technical means in future versions, such as adding Prop declarations.syncOptions, just declaresync: trueAll of them can be assigned directly and automatically triggeredupdate:xxxevent.

Of course, as a framework, when solving a problem, we must also consider the impact on other features and the scalability of the framework. Therefore, we will wait and see how the two-way binding will evolve in the end.

Interested friends can use itOnline HTML/CSS/JavaScript code running toolhttp://tools./code/HtmlJsRunTest the above code running effect.

I hope this article will be helpful to everyone's programming.