preface
In the last section we talk about “Vue source learning (2)” you don’t know – template compilation principle, which is to talk about the template to render function required format, so today, I will tell you, Vue is how to take this thing, to generate the real DOM and display to the page.
code
Step 1.
Graph TD $mount --> mountComponent mountComponent --> _render --> _render --> _render
2. Initialize Vue
const { initMixin } = require('./init')
const { lifecycleMixin } = require('./lifecycle')
const { renderMixin } = require("./render")
function Vue(options) {
this._init(options)
}
initMixin(Vue)
renderMixin(Vue)
lifecycleMixin(Vue)
Copy the code
3. MountComponent (rendering entry)
// lifecycle.js
const { patch } = require('./vdom/patch')
function mountComponent (vm, el) {
vm.$el = el;
// In the previous section, we talked about compiling the template to the render function
// In this section, we need to execute the _render function to call the render function to generate the virtual DOM
// Then receive the return value of the virtual DOM, and call the _update function to convert the virtual DOM into a real DOM and render it
vm._update(vm._render())
return vm
}
function lifecycleMixin(Vue) {
// Hang _update on the Vue prototype
Vue.prototype._update = function (vnode) {
const vm = this
// Execute the patch function, described below
vm.$el = patch(vm.$el, vnode) || vm.$el
}
}
module.exports = {
mountComponent,
lifecycleMixin
}
Copy the code
4. _render function (execute the render function to get the virtual DOM)
// render.js
const { createElement, createTextNode } = require('./vdom/index')
function renderMixin(Vue) {
// Hang the _render function on the Vue prototype
Vue.prototype._render = function() {
const vm = this
// Remove the render function generated in the previous section
const { render } = vm.$options
// Execute the render function and get the virtual DOM
const vnode = render.call(vm)
return vnode
}
// Create the element node virtual DOM
Vue.prototype._c = function(. args) {
returncreateElement(... args) }// Create a text node virtual DOM
Vue.prototype._v = function (text) {
return createTextNode(text)
}
// In the case of an object, convert the object to a string
Vue.prototype._s = function (val) {
return val === null ? ' ' : typeof val === 'object' ? JSON.stringify(val) : val
}
}
module.exports = {
renderMixin
}
Copy the code
Below are the specific functions and classes required to create the virtual DOM
// vdom/index.js
// Create a virtual DOM for a node
class Vnode {
constructor(tag, data, key, children, text) {
this.tag = tag
this.data = data
this.key = key
this.children = children
this.text = text
}
}
// Create the element node virtual DOM
function createElement(tag, data= {}, ... children) {
const key = data.key
return new Vnode(tag, data, key, children)
}
// Create a text node virtual DOM
function createTextNode(text) {
return new Vnode(undefined.undefined.undefined.undefined, text)
}
module.exports = {
createElement,
createTextNode
}
Copy the code
5. Patch function (transform virtual DOM into real DOM and render)
// vdom/patch.js
function patch(oldVnode, vnode) {
// This section covers only the first render
// oldVnode is the EL node for the first rendering, and oldVnode is the last virtual DOM for all subsequent non-first rendering
// Determine the type of oldVnode
const isRealElement = oldVnode.nodeType
if (isRealElement) {
// First render
const oldElm = oldVnode
const parentElm = oldElm.parentNode
// Generate real DOM objects
const el = createElm(vnode)
// The real DOM to be generated. Insert before the next node of the EL
// Insert after el
// Not directly appendChild because there may be other EL siblings on the page and the order cannot be broken
parentElm.insertBefore(el, oldElm.nextSibling)
// Delete the old EL node
parentElm.removeChild(oldVnode)
return el
}
}
// The virtual DOM generates the real DOM
function createElm(vnode) {
const { tag, data, key, children, text } = vnode
// Determine whether it is an element node or a text node
if (typeof tag === 'string') {
// Create a label
vnode.el = document.createElement(tag)
// Parse virtual DOM properties
updateProperties(vnode)
// Recursively, the child node also generates the real DOM
children.forEach(child= > {
return vnode.el.appendChild(createElm(child))
})
} else {
// The text node is created directly
vnode.el = document.createTextNode(text)
}
return vnode.el
}
// Parse the properties of the virtual DOM
function updateProperties(vnode) {
const newProps = vnode.data || {}
const el = vnode.el
for(let key in newProps) {
if (key === 'style') {
// Style of processing
for (let styleName in newProps.style) {
el.style[styleName] = newProps.style[styleName]
}
} else if (key === 'class') {
// Class processing
el.className = newProps.class
} else {
// Call dom setAttribute to set the attributes
el.setAttribute(key, newProps[key])
}
}
}
module.exports = {
patch
}
Copy the code
6. Specific flow chart
conclusion
I also do not know will not be someone to see, anyway, it is finished!! Come on!!
- Do you want to know how Vuex works?
- Do you really know how a Slot is “inserted”
- “Vue source learning (a)” you don’t know – data responsive principle
- “Vue source learning (2)” you do not know – template compilation principles
- “Vue source learning (3)” you don’t know – first rendering principles
Study group, touch fish, come in to talk and laugh
Please click the link here