Recently, The author of Ant Design Vue, Tang Jinzhou, opened a class on a platform and systematically described the development of Vue in the whole course. In the eighth lecture, I introduced the problem of Vue bidirectional binding. Here I sorted out some data and objectively analyzed whether the principle of Vue data response is bidirectional binding.


Many students understand the data response principle of Vue as bidirectional binding when they understand Vue, but in fact, this is not accurate. The data response we mentioned before drives the change of DOM view through the change of data, while bidirectional binding in addition to data-driven DOM, DOM changes in turn affect data. Is a bidirectional relationship. In Vue, we can implement bidirectional binding via v-Model.

There are two ways in which bidirectional binding can be implemented in Vue. Before analyzing it, let’s discuss the differences between the two ways.

1) V-model attributes

2).sync modifier

v-model

2.2.0 + added

By default, a V-Model on a component makes use of a prop named Value and an event named input, but input controls like checkboxes, checkboxes, and so on May use the value feature for different purposes. The Model option can be used to avoid such conflicts:

ChildBox.vue

<template>
  <input type="checkbox"
         :checked="checked"
         @change="$emit('change', $event.target.checked)"/>
</template>

<script>
export default {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  }
}
</script>
Copy the code

Index.vue

<template>
  <div>
    <ChildBox v-model="val"/>
    <! -->
    <ChildBox :value="val"
              @change="data => (val = data)"/>
  </div>
</template>
Copy the code

Analyze the code above. The childBox. vue file simply wraps the checkbox, providing the checked parameters. The index. vue file is the parent component that references ChildBox as its own child component. Note here. The binding of val values uses v-model instead of V-bind :checkbox. In the beginning we said that there are two kinds of bidirectional binding: v-Model and.sync. If v-model is used, the props of the child component should be set to value and the pass up should be $emit(‘input’). So there is another important point here, the role of model.

model

2.2.0 new

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.

The sync modifier

2.3.0 + added

In some cases, we may need to “bidirectional bind” a prop. Unfortunately, true bidirectional binding creates maintenance problems, because child components can modify the parent, and there is no obvious source of change in either parent or child.

This is why we recommend replacing the schema triggering event with update:myPropName. For example, in a component that contains a title prop hypothesis, we can express the intent to assign a new value to it as follows:

ChildBox.vue

<template>
  <input type="checkbox"
         :checked="checked"
         @change="$emit('update:checked', $event.target.checked)"/>
</template>

<script>
export default {
  props: {
    checked: Boolean
  }
}
</script>
Copy the code

Index.vue

<template>
  <div>
    <ChildBox :checked.sync="val"/>
    <! -->
    <ChildBox :checked="val"
              @update:checked="data => (val = data)"/>
  </div>
</template>
Copy the code

What has changed in the code above, parentv-modelbe:checked.syncReplace. Child component is not applicablev-model, so no Model configuration is required. Change function toEvent. Target. Checked).

V-model source code analysis

Reveal the secrets with ustBhuangyi Vue.js technology. Here is only a summary comparison, detailed analysis of the process can see the link.

Take the following code for example:

let vm = new Vue({
  el: '#app'.template: '<div>'
  + '<input v-model="message" placeholder="edit me">' +
  '<p>Message is: {{ message }}</p>' +
  '</div>',
  data() {
    return {
      message: ' '}}})Copy the code

The V-Model attribute is set on the input element, which is bound to Message, which changes when we enter something on the input.

Generate function

function generate (ast, options) {
  var state = new CodegenState(options);
  var code = ast ? genElement(ast, state) : '_c("div")';
  return {
    render: ("with(this){return " + code + "}"),
    staticRenderFns: state.staticRenderFns
  }
}
Copy the code

For our example, the resulting render code looks like this:

with(this) {
  return _c('div',[_c('input', {directives: [{name:"model".rawName:"v-model".value:(message),
      expression:"message"}].attrs: {"placeholder":"edit me"},
    domProps: {"value":(message)},
    on: {"input":function($event){
      if($event.target.composing)
        return;
      message=$event.target.value
    }}}),_c('p',[_v("Message is: "+_s(message))])
    ])
}
Copy the code

Eventually translated to:

<input
  v-bind:value="message"
  v-on:input="message=$event.target.value">
Copy the code

Dynamically binding the input value to the Messgae variable, and dynamically setting message to the target value when the input event is triggered, effectively binding the data in both directions, so the V-model is essentially a syntax sugar.

Ustbhuangyi also introduced in detail the realization principle of V-Model in components in vue. js technology disclosure, here is not more than the statement.

conclusion

We learned that the V-Model is a true implementation of Vue bidirectional binding, but is essentially a syntactic sugar that can support both native form elements and custom components. In the component implementation, we can configure the prop name that the child component receives, and the event name that it dispatches.

Finally, both V-Model and.sync can implement bidirectional data binding, so which one makes more sense? Feel free to comment with your opinion.

Wish you progress in study

Wen-bin deng

March 21, 2019