new Vue
The instance
The whole process
Initialization and responsive processing of data
// The overall process
new Vue()
this._init(options)
// Call the _init method bound in initMixin(Vue)
Vue.prototype._init = function(options) { const vm = this }
// a series of initialization operations initLifecycle, initEvents, initRender... initState, ...
/ / a mount
vm.$mount(vm.$options.el) // #app
Copy the code
// Focus on the initState method
export function initState(vm) {
/ / merge options
vm.$options = mergeOptions( ... )
const opts = vm.$options
initProps(vm, opts.props)
initMethods(vm, opts.methods)
initData(vm) / / concerns
initComputed(vm, opts.computed)
initWatch(vm, opts.watch)
}
Copy the code
/ / initData method
function initData(vm) {
const data = vm.$options.data
// whether data is function, note vm._data
data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {}
// Check if the property conflicts with the properties defined in props, methods
const keys = Object.keys(data)
// ...
// Pass this._data. XXX to this.xxx via object.defineProperty
// get: return this._data.xxx
// set: this._data.xxx = val
proxy(vm, `_data`, key)
// Reactive processing
observe(data, true /* asRootData */)}Copy the code
Vue
Examples of the mount
/ / Add vNode to vNode (vm._update()); / / add vNode to vNode (vm._update()); / / Add vNode to vNode (vm._update())
The version entry for analysis is entry-runtime-with-compiler.js
const mount = Vue.prototype.$mount // Cache - Runtime only Version uses the mount method directly
Vue.prototype.$mount = function() {} // redefine
// render and template respectively
// Will be converted to render function
const { render } = compileToFunctions()
vm.$options.render = render
// Call the $mount method on the original prototype (i.e. cached) to mount it
return mount.call(this, el, hydrating) // The hydrating server render is relevant. Default is false
Execute the mountComponent method in the mount method
return mountComponent(this, el, hydrating)
Copy the code
The mountComponent method does two main things
Call vm._render() to generate a virtual node
const vnode = vm._render()
// 2. Instantiate watcher and call updateComponent - initialization & data changes are performed
new Watcher(vm, updateComponent, noop, {}, true)
updateComponent = () = > {
vm._update(vm._render(), hydrating) / / update the dom
}
// The process ends, changing the state
vm._isMounted = true
callhook(vm, 'mounted')
Copy the code
render
function
src/core/instance/render.js
Vue.prototype._render = function() {
const vm = this
// The entry section handles the render function
const { render } = vm.$options
// Core part -vm.$createElement
vnode = render.call(vm._renderProxy, vm.$createElement)
return vnode
}
The $createElement method is defined in initRender(vm)
Copy the code
// examples of projects using the render function
import Vue from 'vue'
new Vue({
el: '#app'.// createElement -> vm.$createElement
render: function(createElement) {
return createElement('div', {
attrs: {
id: 'app'}},this.message)
},
data() {
return {
message: 'hello, vue'}}})Copy the code
virtual dom
Native JS objects to describe a DOM node refer to the open source library SnabbDOM
createElement
Create a VNode SRC/core/vdom/create – element. Js
// Encapsulate one layer of _createElement
export function createElement() {
return _createElement(context, tag, data, children, normalizationType)
}
// context - VNode 上下文环境: Component
// data - VNode 数据: VNodeData
// children -vnode child: any - needs to be normalized as a standard VNode array
/ / normalizationType - byte point specification types - 【 】 to distinguish function compiled | | written by the user
Copy the code
// src/core/instance/render.js
export function initRender(vm) {
vm._c(vm, a, b, c, d, false) // render functions complied from template.
vm.$createElement(vm, a, b, c, d, true) // user-written render functions.
}
/ / normalizationType category
// false - simpleNormalize
// true - alwaysNormalize
// To sum up
// render functions generate - false - simple - call simpleNormalizeChildren
// render functions are user handwriting - true-always - call normalizeChildren
Copy the code
// src/core/vdom/helpers/nomalize-children.js
export function simpleNormalizeChildren(children) {
// The default VNode type, but functional components return arrays instead of roots
// 1-level deep
for(let i = 0; i < children.length; i++) {
if(Array.isArray(children[i])) {
return Array.prototype.concat.apply([], children)
}
}
return children
}
// Two scenarios
// 1. User handwriting, children only have one node, create simple text node
// 2.
,
, v-for generates nested arrays
export function normalizeChildren(children) {
return isPrimitive(children) // Whether it is a basic type
? [createTextVNode(children)] // Create simple text nodes
: Array.isArray(children)
? normalizeArrayChildren(children)
: undefined
}
export function normalizeArrayChildren(children) {
/ / traverse the children
// Call this method recursively if the child node c is Array
// Call createTextVNode() if child c is of base type
// opt: If there are consecutive text nodes, they are merged into a single text node
}
Copy the code
/ / create a VNode
if(typeof tag === 'string') {
// 1. Built-in node
vnode = new VNode(parsePlatformTagName(tag), data, children, undefined.undefined, context)
// 2. Registered component name
vnode = createComponent(Ctor, data, context, children, tag)
// 3. Unknown node
vnode = new VNode(tag, data, children, undefined.undefined, context)
} else {
vnode = createComponent(tag, data, context, children)
}
return vnode
// vm._render() completes the process
Copy the code
update
Core – vm. Patch () for the first time rendering – concerns data update – reactive principle of SRC/core/instance/lifecycle. Js
Vue.prototype._update = function(vnode, hydrating) {
// Core part
vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false)}// src/platforms/web/runtime/index.js
Vue.prototype.__patch__ = inBrowser ? patch : noop // There is no DOM environment for server rendering
// src/platforms/web/runtime/patch.js
export const patch = createPatchFuntion({nodeOps, modules }) // Patch is implemented
Copy the code
// src/core/vdom/patch.js
export function createPatchFunction(backend) {
// Core - Create a real DOM from a virtual node and insert a parent node
createElm() {
// Iterate over the child virtual nodes recursively - depth-first
// Recursively, child elements take precedence over insert, so the insertion order of vNode tree is parent before child
createChildren()
}
}
// Invoke native DOM API operations
function insert(parent, ele, ref) {
// e.g.
// insertBefore()
// appendChild()
}
Copy the code
The main process is shown in the figure below