The overall process of template compilation: compile the template into the render function using Vue Template Complier, and then execute the render function to generate a VNode

Pre-knowledge: JSwithgrammar

  • withSyntax changes{}Search rules for free variables in a block, asobjProperty to find
  • If you don’t find a matchobjProperty, an error is reported
  • withUse it with caution, it breaks scope rules and makes it less legible

vue template complierCompile the template torenderfunction

What are vue templates compiled into?

  1. Template is not HTML, there are instructions, interpolation, JS expression, can realize the judgment, loop
  2. HTML is a tag language, only JS can implement judgment, loop (Turing-complete)
  3. Therefore, the template must be converted to some kind of JS code, how to convert a template to JS code process is template compilation

First we install vue Template Complier, and then we write a template string to see the compiled output

The interpolation to compile

const compiler = require('vue-template-compiler')
/ / the interpolation
// const template = ` 

{{message}}

`
/ / compile const res = compiler.compile(template) console.log(res.render) Copy the code

The print result is as follows

with(this){return _c('p',[_v(_s(message))])}
Copy the code

This is the VM instance in Vue, so _c _V _S is some functions in vue source code, so let’s search the meaning of these functions in the source code

// Find the meaning of the abbreviation function in vue source code
function installRenderHelpers (target) {
    target._c = createElement/ / create a vnode
    target._o = markOnce;
    target._n = toNumber;
    target._s = toString;
    target._l = renderList;
    target._t = renderSlot;
    target._q = looseEqual;
    target._i = looseIndexOf;
    target._m = renderStatic;
    target._f = resolveFilter;
    target._k = checkKeyCodes;
    target._b = bindObjectProps;
    target._v = createTextVNode;
    target._e = createEmptyVNode;
    target._u = resolveScopedSlots;
    target._g = bindObjectListeners;
    target._d = bindDynamicKeys;
    target._p = prependModifier;
}
Copy the code

So the transformation is as follows

with(this){return createElement('p',[createTextVNode(toString(message))])}
Copy the code

The createElement function creates a VNode

Expression compilation

The expression is converted to JS code and the result is put into a VNode

const template =  ` <p>{{flag ? message : 'no message found'}}</p> ` 
Copy the code
with(this){return _c('p',[_v(_s(flag ? message : 'no message found')))}Copy the code

Dynamic properties

In the same way

// Dynamic attributes
const template =  ` 
      
`
Copy the code

with(this){return _c('div',
     {staticClass:"container".attrs: {"id":"div1"}},
     [
         _c('img', {attrs: {"src":imgUrl}})])}
Copy the code

conditions

Use ternary expressions to create different VNodes

/ / conditions
const template =  ` 
      

A

B

`
with(this){return _c('div',[(flag === 'a')? _c('p',[_v("A")]):_c('p',[_v("B")]])}Copy the code

cycle

The _L (renderList) function returns the list vNode by passing in an array or object

/ / loop
const template =  ` 
      
  • {{item.title}}
`
with(this){return _c('ul',_l((list),function(item){return _c('li', {key:item.id},[_v(_s(item.title))])}),0)} Copy the code

The event

The ON property contains all the event bindings

/ / event
const template =  `  ` 
with(this){return _c('button', {on: {"click":clickHandler}},[_v("submit")])}
Copy the code

v-model

//v-model
const template =  ` <input type="text" v-model="name"> ` 
// Look at the input event
with(this){return _c('input', {directives: [{name:"model".rawName:"v-model".value:(name),expression:"name"}].attrs: {"type":"text"},domProps: {"value":(name)},on: {"input":function($event){if($event.target.composing)return; name=$event.target.value}}})}Copy the code
  • There’s one in the compiled codeonAnd to monitor theinputThe event,name=$event.target.valueDelegate assigns the value of the event tonamethenameIs in the component instancename, i.e.,this.name
  • domProps:{"value":(name)}On behalf ofvalueShows thenameVariables, alsothis.name

In other words, the principle of the V-model is the attr of value plus the syntax sugar of the input event, and then execute the render function to generate the VNode

conclusion

Template compilation process: the template is compiled into the render function, executes the render function to return vNode

Patch and DIff will be implemented later based on vNode (see my article Vue series: Virtual DOM and Diff algorithm in detail).

Note: With Webpack vue-loader, templates are compiled in a development environment (important). So the resulting packaged code is no longer template code, but all render functions. But the vue. Js file that we reference directly with

renderfunction

You can use Render instead of template in vue components

In complex cases where template is not available, use render instead

To summarize how components are rendered and updated

The component rendering/update process wraps three things:

  • Initial rendering process
  • The update process
  • Asynchronous rendering

The initial rendering process

  1. Parsing the template into the render function (webpack uses vue-Loader in the development environment) (this process is how the template compilation works above)

  2. Firing responsivity, listening for data properties, setting getter setters (see my article Vue series: Vue2 Responsivity Principles)

  3. Execute the render function to generate the VNode, and then execute patch(elem, vnode) to render the VNode to the DOM. Take a closer look at my Vue series: Virtual DOM and Diff Algorithms

The update process

  1. Modify thedataTo triggersetter(aftergetterIs being monitored)
  2. To performrenderFunction, generatenewVnode
  3. patch(vnode, newVnode)(Diff algorithm)

Summary render update flowchart

The template compiles and then executes the render function, which fires the reactive getter for dependency collection (watcher the getter for any variable fired in the template).

When we modify the data, we fire the setter and notify the Watcher to refire the re-reder for rerendering

Vue components are rendered asynchronously

Review thethis.$nextTick

  1. Vue components are rendered asynchronously. DOM will not render immediately until the code is executed.this.$nextTickIs called back when DOM rendering is complete
  2. The page will be rendereddataMake an integration of the modifications, multiple timesdataOnly one final value will be rendered

This reduces DOM operations and improves performance