“This is my 36th day of participating in the First Challenge 2022. For details: First Challenge 2022.”
Previously on & Background
A small essay introduces the Vue ahead at compile time for < slot > this placeholder tag a processing, compile slot label finally got a called _t rendering function runtime help function invocation: _t (slotName, children, attrs, bind);
SlotName is the name attribute value on the slot tag of a named slot. For an anonymous slot, slotName is default.
Children are children of the slot tag; Although the slot is not shown when it is eventually used, the slot’s child elements are still rendered for placeholder cues when the component is referenced without passing the slot’s contents.
We have described rendering functions in the following cases:
- Static root node rendering function, promoted to
staticRenderFns
The array; - with
v-model
ηinput
Render functions that deal with different elements,input
Dynamic bindingtype
Is the type of the different event handling types and binding values; - with
v-if/v-else-if/v-else
Condition rendering, according toel.ifConditons
Deal with the ternary expression of the set of children; - with
v-for
List rendering, according toel.for
εel.alias
Processing into_l(el.for, function (it1,it2) {return _c(...) })
The call; - Handle tag rendering if
el.tag
To obtain theslotName
Processing into_t(slotName,children...)
Second, the processing of custom components
In our test.html we have a
2.1 example test. HTML
<div id="app">
<some-com :some-key="forProp">
<div>SomeCom slot contents</div>
</some-com>
</div>
Copy the code
2.2 genElement handles custom components
There is not much difference between handling custom components and native HTML elements in the render function of the root instance. It is handled in the else of the genElement, including dynamic components.
export function genElement (el: ASTElement, state: CodegenState) :string {
if (el.parent) {
} else {
// This else handles: dynamic components, normal elements, custom components
let code
if (el.component) {
code = genComponent(el.component, el, state)
} else {
let data
if(! el.plain || (el.pre && state.maybeComponent(el))) {// Non-ordinary elements or components with v-pre instructions go here, process all the attributes of the node, return a JSON string,
Key: xx, ref: xx,.... } '
data = genData(el, state)
}
// Get an array of code for all the child nodes in the string format:
// `['_c(tag, data, children)', ....] , normalizationType`
const children = el.inlineTemplate ? null : genChildren(el, state, true)
code = `_c('${el.tag}'${
data ? `,${data}` : ' ' // data
}${
children ? `,${children}` : ' ' // children
}) `
}
for (let i = 0; i < state.transforms.length; i++) {
code = state.transforms[i](el, code)
}
return code
}
}
Copy the code
You can see that in the picturegenElement
Into theelse
And elThe tag name
el.tagis
some-comAs can be seen from the example,
some-compComponent references pass in slot content for distribution:
, so
The slot content is also rendered as a normal child node, with the above slot rendering function as follows:
"[_c('div',[_v(\"someCom socket contents \")])]"
Copy the code
Combining the above results, we get the code for the some-com component’s rendering function:
"_c (- com ', '{attrs: {\" some - key \ ": forProp}}, [_c (' div', [_v (\" someCom slot content \ ")])])"
Copy the code
GenElement handles dynamic components
You will always encounter dynamic component scenarios in your daily development. This is actually a good thing, and it gives developers a lot of imagination and play. The server can even return a string that corresponds to a specific view.
But it also makes it seem mysterious, so let’s find out today;
3.1 Examples of test.html
<div id="app">
<component is="someCom">
<div>The componet of the slot</div>
</component>
</div>
Copy the code
3.2 genElement δΈη genComponent
The logic that genElement handles dynamic components is also handled in else, and the logic that el.componenthas a value is the part that handles dynamic components
export function genElement () :string {
if (el.parent) {
} else {
let code
if (el.component) {
// el.component.ponet is the value of the DYNAMIC component binding's IS property, which is the component name
code = genComponent(el.component, el, state)
} else {
return code
}
}
Copy the code
3.3 genCompoent
Methods location: SRC/compiler/codegen/index. Js – > genComponent
Method parameters:
componentName
: Component name, that isis
The value of the property binding;el
:ast
Node object;state
:CodegenState
Instance;
The < Component >
method generates a render function for the < Component > dynamic component.
- To deal with
component
Gets the child element ofRender function
An array of code; - Concatenates the current dynamic component to
componentName
The rendering function code for the component looks like this:_c(compName, data, children)
function genComponent (componentName: string, el: ASTElement, state: CodegenState) :string {
const children = el.inlineTemplate ? null : genChildren(el, state, true)
return `_c(${componentName}.${genData(el, state)}${
children ? `,${children}` : ' '
}) `
}
Copy the code
Four,
This essay discusses the corresponding rendering functions of two other commonly used functions: custom components and dynamic components.
Both are processed into _C (componentName, data, children) call form;
Somewhat disappointingly, we realize that this is no different from rendering a normal div. What about custom components? What about the life cycle?
Don’t worry, as I mentioned earlier we are now dealing with the rendering function of the root instance. This custom component is a subinstance and it is not initialized at this time. So when does this subinstance get initialized? At this point in the compilation phase of the root instance, only when the compilation phase of the root instance is finished, the rendering function of the root instance is available, and then the rendering function of the root instance is created by Watcher.
_c/ _L /_t/ _S /_v… When executed, these helper functions, if encountered with a custom component, will proceed to create a new Vue instance. Creating a new Vue instance will redo the _init logic of the Vue including processing the data responsivity, compiling the template to generate the AST to get the subinstance render function. Wathcer executes the render function of the subinstance to get the DOM and then completes the mount.