Rendering functions in the MVVM framework are created by compiling view templates, which are simply parsed to generate rendering functions.
directory
- What is the virtual Dom
- What is a render function
- DomDiff updates views efficiently
- 【 Render function 】
The render module uses render functions to generate the virtual Dom from initialization data
->Create view page Html using the virtual Dom
->Once the data model changes, the rendering function is called again to generate a new virtual Dom and then do Dom Diff to update the view Html
- 【 Render function 】
Initialize data
->Render (initialize data)
->Initialize the virtual DOM
->Initial view HTML
->Data changes
->Render (change data)
->New virtual DOM
->DOM Diff
->Update view HTML
- Template -> compiles to render function -> converts to virtual Dom
-
- Template -> render -> virtual Dom
What is the virtual Dom
1) dom
Dom has a large number of nodes, so the performance of directly querying and updating Dom is poor
2) virtual Dom
A way of representing the actual DOM with JavaScript Objects. Rerepresent the actual Dom with a JS object
What is a render function
In Vue we compile a view template into a render function and then convert it into a virtual Dom
Update views efficiently with DomDiff
Four, achieve the rendering function [key]
In Vue we compile a view template into a render function and then convert it into a virtual Dom
4.1) The rendering process is usually divided into three parts:
- RenderPhase: The render module uses render functions to generate the virtual Dom from initialization data
- MountPhase: Create view page Html using the virtual Dom
- PatchPhase: Once the data model changes, the rendering function will be called again to generate a new virtual Dom and then do Dom Diff to update the view Html
mount: function (container) {
const dom = document.querySelector(container);
const setupResult = config.setup();
const render = config.render(setupResult);
let isMounted = false;
let prevSubTree;
watchEffect(() = > {
if(! isMounted) { dom.innerHTML ="";
// mount
isMounted = true;
const subTree = config.render(setupResult);
prevSubTree = subTree;
mountElement(subTree, dom);
} else {
// update
constsubTree = config.render(setupResult); diff(prevSubTree, subTree); prevSubTree = subTree; }}); }Copy the code
4.1.1) 1 Render Phase
The render module uses render functions to generate the virtual Dom from initialization data
render(content) {
return h("div".null, [
h("div".null.String(content.state.message)),
h(
"button",
{
onClick: content.click,
},
"click"),]); },Copy the code
4.1.2) 2 Mount Phase
Create view page Html using the virtual Dom
function mountElement(vnode, container) {
// Render to a real DOM node
const el = (vnode.el = createElement(vnode.type));
/ / processing props
if (vnode.props) {
for (const key in vnode.props) {
const val = vnode.props[key];
patchProp(vnode.el, key, null, val); }}// Handle children
if (Array.isArray(vnode.children)) {
vnode.children.forEach((v) = > {
mountElement(v, el);
});
} else {
insert(createText(vnode.children), el);
}
// Insert into the view
insert(el, container);
}
Copy the code
4.1.3) 3 Patch Phase(Dom diff)
Once the data model changes, the rendering function is called again to generate a new virtual Dom and then do Dom Diff to update the view Html
function patchProp(el, key, prevValue, nextValue) {
// onClick
// 1. If the first two values are on
// 2. Consider it an event
// 3. On is the corresponding event name
if (key.startsWith("on")) {
const eventName = key.slice(2).toLocaleLowerCase();
el.addEventListener(eventName, nextValue);
} else {
if (nextValue === null) {
el.removeAttribute(key, nextValue);
} else{ el.setAttribute(key, nextValue); }}}Copy the code
Update views with DomDiff – Efficiently
function diff(v1, v2) {
// 1. If the tag is different, just replace it
// 2. If tag is the same
// 1. Check whether the props are changed
// 2. To detect children -
const { props: oldProps, children: oldChildren = [] } = v1;
const { props: newProps, children: newChildren = [] } = v2;
if(v1.tag ! == v2.tag) { v1.replaceWith(createElement(v2.tag)); }else {
const el = (v2.el = v1.el);
/ / contrast props
// 1. The new node is not equal to the value of the old node -> direct assignment
// 2. Delete all keys that do not exist in the new node
if (newProps) {
Object.keys(newProps).forEach((key) = > {
if (newProps[key] !== oldProps[key]) {
patchProp(el, key, oldProps[key], newProps[key]);
}
});
// Go through the old node - "new node does not have, then delete all
Object.keys(oldProps).forEach((key) = > {
if(! newProps[key]) { patchProp(el, key, oldProps[key],null); }}); }/ / the children
// newChildren -> string
// oldChildren -> string oldChildren -> array
// newChildren -> array
// oldChildren -> string oldChildren -> array
if (typeof newChildren === "string") {
if (typeof oldChildren === "string") {
if (newChildren !== oldChildren) {
setText(el, newChildren);
}
} else if (Array.isArray(oldChildren)) {
// Replace all the previous elementsv1.el.textContent = newChildren; }}else if (Array.isArray(newChildren)) {
if (typeof oldChildren === "string") {
// Clear the previous data
n1.el.innerHTML = "";
// Mount all the children out
newChildren.forEach((vnode) = > {
mountElement(vnode, el);
});
} else if (Array.isArray(oldChildren)) {
// a, b, c, d, e -> new
// a1,b1,c1,d1 -> old
// If there are too many new, create a new one
// a, b, c -> new
// a1,b1,c1,d1 -> old
// If there are many old ones, delete all the old ones
const length = Math.min(newChildren.length, oldChildren.length);
for (let i = 0; i < length; i++) {
const oldVnode = oldChildren[i];
const newVnode = newChildren[i];
// Can be very complex
diff(oldVnode, newVnode);
}
if (oldChildren.length > length) {
// Indicates that there are many old nodes
// Delete all of them
for (leti = length; i < oldChildren.length; i++) { remove(oldChildren[i], el); }}else if (newChildren.length > length) {
// Indicates that new has many nodes
// Then you need to create the corresponding node
for (let i = length; i < newChildren.length; i++) {
mountElement(newChildren[i], el);
}
}
}
}
}
}
Copy the code
reference
- Vue source
conclusion
- Virtual Dom – Rerepresents the actual Dom with JS objects
- [Rendering function process]
Once the data model changes, the rendering function will be called again to generate a new virtual Dom, and then do Dom Diff to update the view Html
- [Rendering function process]
Initialize data -> render -> initialize virtual DOM -> initial view HTML -> data changes -> render -> new virtual DOM -> DOM Diff -> update view HTML
- Template -> compiles to render function -> converts to virtual Dom
- Template -> render -> virtual Dom
- Rendering functions in the MVVM framework are created by compiling view templates, which are simply parsed to generate rendering functions.