This article focuses on bidirectional binding, not reactive


preface

I am not very clear about the concept of bidirectional binding. I am in a state of “following the herd”. I want to explain but cannot achieve a good level of presentation and cannot clearly explain this concept. So I had the idea to write this article. Personally, if the narrator is not clear, coherent and straightforward about something, it means that he himself does not understand the matter very thoroughly.

Bidirectional binding concept

View and data synchronization.

This is my understanding of the concept of bidirectional binding. So since there are bidirectional binding, then some students may wonder: is there a one-way, three-way [manual funny]… ? One-way is basically what many frameworks do from the Model -> View solution, and most of the mainstream frameworks do this at their core.

As for three-way or more bindings, I can’t think of anything that needs to be synchronized with the view…

Use Vue’s bidirectional binding

Since everyone uses input type=text for presentation, I will use multi-check box to 🙋 🌰 (for example).

<div id="app">
  <ol>
    <li v-for="item in options">
      <label>
        <input type="checkbox" v-model="selected" :value="item">
          {{ item }}
      </label>
    </li>
  </ol>
  <p>{{selected}}</p>
</div>Copy the code
New Vue ({el: "# app," data: {options: [" eat ", "sleeping", "LOL"], selected: [" LOL "]}})Copy the code

When we initialize, “LOL” will be selected, which is Model -> View. When we select the other two items, View -> Model will be triggered, and the selected value will be updated synchronously. Of course, Vue listens to the Model change, triggers the render of the component, performs the VDOM comparison of the component, and synchronizes the view value of the P tag.

How is the Vue bidirectional binding magic implemented

Vue V2 started with one-way data, and the V-model was a syntactic sugar for rapid development, which was changed when the template was compiled. Of course, different elements and types can be compiled differently.

So let’s compile the above snippet and see what happens. Tip: template syntax always ends up as render functions!

// Node script const compiler = require('vue-template-compiler') const template = '<div id="app"> <ol> <li V -for="item in options"> <label> <input type="checkbox" v-model="selected" :value="item"> {{ item }} </label> </li> </ol> <p>{{selected}}</p> </div>` const compileToFunctionsResult = compiler.compileToFunctions(template) console.log(compileToFunctionsResult.render)Copy the code

The output below has been formatted

function anonymous() { with(this) { return _c('div', { attrs: { "id": "app" } }, [_c('ol', _l((options), function(item) { return _c('li', [_c('label', [_c('input', { directives: [{ name: "model", rawName: "v-model", value: (selected), expression: "selected" }], attrs: { "type": "checkbox" }, domProps: { "value": item, "checked": Array.isArray(selected) ? _i(selected, item) > -1 : (selected) }, on: { "change": function($event) { var ?a = selected, ?el = $event.target, ?c = ?el.checked ? (true) : (false); if (Array.isArray(?a)) { var ?v = item, ?i = _i(?a, ?v);  if (?el.checked) { ?i < 0 && (selected = ?a.concat([?v])) } else { ?i > -1 && (selected = ?a.slice(0, ?i).concat(?a.slice(?i + 1))) } } else { selected = ?c } } } }), _v("\n " + _s(item) + "\n ")])]) })), _v(" "), _c('p', [_v(_s(selected))])]) } }Copy the code

From the compiled code, we can make it clear that the V-Model is compiled into template syntax like this.

<input :checked="selected.indexOf(item) > -1" @change="change"/>Copy the code

Of course, the processing of multiple options is different from that of text boxes. After change is triggered, multiple options will be added and deleted for arrays.

Vue shields the underlying differences of various input, abstracts the syntax of v-Model, and reduces the amount of code in our development process, which is also great

further

We know that Vue does this for native tags, but what about components?

The equivalent of v-model is written as follows

<self-component :value="value" @input="value=arguments[0]"/>Copy the code

Pass the value attribute; Listen for input events and update Model values when triggered. Perfect!

Of course, you can customize the v-Model mapping field name in the component, which is the default

export default {
    model: {
        prop: 'value',
        event: 'input'
    },
    ...
}Copy the code

conclusion

Know what it is and why

Mutual encouragement, continue to progress! 😀