Form v – model

In VUE, v-Model is undoubtedly one of the most commonly used apis, such as input, Textarea, radio, Checkbox, select, etc., can use V-Model for bidirectional binding. So how exactly does it work? Below through oneself write a demo to analyze concretely?

directives

The instructions defined on the elements are collected during vue’s parse phase, which is the process of generating code from the AST tree

model = $event.target.value
Copy the code

Going back to genDefaultModel, two very important methods will be executed

  addProp(el, 'value', ("(" + value + ")"));
  addHandler(el, event, code, null, true);
Copy the code

The first method, addProp, adds a prop to the input tag, dynamically binding the value to it. The second method, addHandler, adds an input event to the input tag and dynamically modifs the model value when the event is triggered. In this way, bidirectional binding is implemented.

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

Finally, back to the genDirectives, a render function is generated according to the directives

V – model components

let baseSpan = {
  template: '
      
+ '< button@click ="changeValue">, props: ['value'], name: 'baseSpan'.data() {return { isShow: this.value } }, methods: { changeValue() { this.isShow = true this.$emit('input'.true) } } } var app = new Vue({ el: '#app', data: { visible: false }, components: { baseSpan } }) Vue.component('base-span',baseSpan); Copy the code

The HTML code looks like this

<div id='app'>
    <base-span v-model='visible'></base-span>
      <span>{{visible}}</span>
 </div>
Copy the code

The parent component’s visible data is associated with the child baseSpan V-Model directive, which defines an props for value and a changeValue method that passes data to the parent component by sending an input event. This is typical father-child communication and is necessary for the V-Model to work. Of course, the value and input are not writable. We can customize them in the model configuration of the child component as needed. For example, the event we dispatch can also be a change. So how is the source code designed?


  if (el.component) {
    genComponentModel(el, value, modifiers);
    // component v-model doesn't need extra runtime return false }Copy the code

The component’s V-Model also executes the instruction’s Model function, and then hits the if statement above to execute the genComponentModel(EL, Value, MODIFIERS) method.

function genComponentModel (
  el,
  value,
  modifiers
) {
  var ref = modifiers || {};
  var number = ref.number;
  var trim = ref.trim;

  var baseValueExpression = '? v';
  var valueExpression = baseValueExpression;
  if (trim) {
    valueExpression =
      "(typeof " + baseValueExpression + " === 'string'" +
      "? " + baseValueExpression + ".trim()" +
      ":" + baseValueExpression + ")";
  }
  if (number) {
    valueExpression = "_n(" + valueExpression + ")";
  }
  var assignment = genAssignmentCode(value, valueExpression);

  el.model = {
    value: ("(" + value + ")"),
    expression: ("\" " + value + "\" "),
    callback: ("function (" + baseValueExpression + "{" + assignment + "}")}; }Copy the code

For our example, the following el. Model is generated

 // component v-model
  if (el.model) {
    data += "model:{value:" + (el.model.value) + ",callback:" + (el.model.callback) + ",expression:" + (el.model.expression) + "},";
  }
Copy the code

In this case, the parent component’s Render function will contain configuration items for the child component model, and the child vNode will be created by executing the createComponent function. Then execute the following logic

 // transform component v-model data into props & events
  if (isDef(data.model)) {
    transformModel(Ctor.options, data);
  }

Copy the code

So transformModel basically adds model-bound data visible to data.props. Then add data.model.callback to on.

// transform component v-model info (value and callback) into
// prop and event handler respectively.
function transformModel (options, data) {
  var prop = (options.model && options.model.prop) || 'value';
  var event = (options.model && options.model.event) || 'input'; (data.props || (data.props = {}))[prop] = data.model.value; var on = data.on || (data.on = {});if (isDef(on[event])) {
    on[event] = [data.model.callback].concat(on[event]);
  } else{ on[event] = data.model.callback; }}Copy the code

This is equivalent to the parent passing visible to the child component’s value via props. When the child changes data, the parent is notified to update visible by sending an event. When I click the button, the span in the isShow=true subcomponent is displayed. The visible = true.

You can see both the V-Model of the form element and the V-Model of the component. They are essentially grammatical sugar.

tips

The company is currently using VUE. In my spare time, I write demo by myself and understand the source code of VUE step by step through the method of single step debugging. If there is something wrong, please give me your advice.