This is the 9th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

The preface

Dynamic components will be used in most cases during the development process. When we need to switch state between different components, dynamic components can well meet our needs, the core of which is the use of component tag and IS attribute.

<div id="app">
  <button @click="changeTabs('child1')">child1</button>
  <button @click="changeTabs('child2')">child2</button>
  <button @click="changeTabs('child3')">child3</button>
  <component :is="chooseTabs">
  </component>
</div>

Copy the code
// js var child1 = { template: '<div>content1</div>', } var child2 = { template: '<div>content2</div>' } var child3 = { template: '<div>content3</div>' } var vm = new Vue({ el: '#app', components: { child1, child2, child3 }, methods: { changeTabs(tab) { this.chooseTabs = tab; }}})Copy the code

The example is a basic usage scenario for a dynamic component. When a button is clicked, the view switches between components child1,child2, and child3 based on the this.chooseTabs value.

AST parse

The < Component > interpretation is the same as in the previous articles, starting with the AST parsing phase and not focusing on every detail, but highlighting the differences in the way things are handled in the past. For dynamic component resolution differences, focus on processComponent, which marks the Component property on the final AST tree because of the IS property on the tag.

Function processComponent (el) {var binding; If ((binding = getBindingAttr(el, 'is'))) { } if (getAndRemoveAttr(el, 'inline-template') ! = null) { el.inlineTemplate = true; }}Copy the code

Render function

With the AST tree, the next step is to generate an executable render function from the AST tree. Due to the Component property, the render function is generated along the genComponent branch.

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

The logic for dynamic components is simple: when there is no inline template flag (more on that later), it is concatenated to subsequent child nodes. The only difference is that the first argument to _c is no longer a specified string, but a variable that represents the component

Function genComponent (componentName, EL, state) { Null var children = el.inlinetemplate? null : genChildren(el, state, true); return ("_c(" + componentName + "," + (genData$2(el, state)) + (children ? ("," + children) : '') + ")") }Copy the code

Comparison of ordinary and dynamic components

"with(this){return _c('div',{attrs:{"id":"app"}},[_c('child1',[_v(_s(test))])],1)}"

Copy the code

Render function for dynamic components

with(this){return _c('div',{attrs:{"id":"app"}},[_c(chooseTabs,{tag:"component"})],1)}
Copy the code

To summarize, the difference between a dynamic component and a normal component is:

  1. astPhase addedcomponentProperty, which is the hallmark of a dynamic component
  2. producerenderFunction phase due tocomponentProperty exists, will be executedgenComponentBranch,genComponentExecution functions of dynamic components are treated specially, and unlike normal components,_cThe first argument to is no longer an immutable string, but a specified component name variable.
  3. rendertovnodeThe phase is the same as the flow of a normal component, except that strings are replaced with variables, and there are{ tag: 'component' }thedataProperties. In the examplechooseTabsI’m going to take thetachild1.

There are therenderFunction, the following process from vNode to real node is basically the same as that of ordinary components in terms of flow and thinking. This stage can be reviewed from the previous analysis of component flow