<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
html,body{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="app"></div>
<script src="../dist/vue.js"></script>
<script>
Vue.component("my",{
render(h){
return h('div','我是组件测试组件渲染流程')
}
})
let vm = new Vue({
el:"#app",
render(h){
return h('my')
}
})
</script>
</body>
</html>
流程
// (一)创建全局组件
/* src/core/global-api/assets.js */
1.definition = this.options._base.extend(definition) // 执行
2.this.options[type + 's'][id] = definition // 在vue实例 options上绑定组件名称
/* src/core/global-api/extend.js */
1.Vue.extend (){
// ...
return Sub
} // 执行extend方法并返回Sub
2.const Sub = function VueComponent (options) {
this._init(options)
}
Sub.options = mergeOptions(
Super.options,
extendOptions
) // 创建sub子类并合并vue函数上定义的各种方法
// (二)创建vue对象 (一)创建全局组件
/* src/core/instance/index.js */
1.function Vue (options) {
this._init(options)
} // 创建vue对象并执行_init方法
/* src/core/instance/init.js */
2.Vue.prototype._init = function (options?: Object) {
// ...
initLifecycle(vm) // 绑定父子关系
initEvents(vm) // 初始化时间
initRender(vm) // 初始化渲染
callHook(vm, 'beforeCreate') // 生命周期
initInjections(vm) // inject
initState(vm) // data属性监听 响应式
initProvide(vm) // provide
callHook(vm, 'created') // 生命周期
// ...
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
} // 初始化方法 响应式等 vm.$mount执行挂载
/* src/platforms/web/entry-runtime-with-compiler.js */
3.Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
const { render, staticRenderFns } = compileToFunctions(template, {
outputSourceRange: process.env.NODE_ENV !== 'production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this)
options.render = render
options.staticRenderFns = staticRenderFns
return mount.call(this, el, hydrating)
} // 重写Vue.prototype.$mount方法 解析template模板 绑定到this上 执行原$mount方法
/* src/platforms/web/runtime/index.js */
4.Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
} // 执行mountComponent
/* src/core/instance/lifecycle.js */
5.export function mountComponent (
vm: Component,
el: ?Element,
hydrating?: boolean
): Component {
callHook(vm, 'beforeMount')
updateComponent = () => {
vm._update(vm._render(), hydrating)
}
new Watcher(vm, updateComponent, noop, {
before () {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, 'beforeUpdate')
}
}
}, true /* isRenderWatcher */)
} // 创建组件渲染Watcher
/* src/core/observer/watcher.js */
6.export default class Watcher {
constructor (){
if (typeof expOrFn === 'function') {
this.getter = expOrFn
}
this.value = this.lazy
? undefined
: this.get()
}
get () {
pushTarget(this)
let value
const vm = this.vm
try {
value = this.getter.call(vm, vm)
} catch (e) {
if (this.user) {
handleError(e, vm, `getter for watcher "${this.expression}"`)
} else {
throw e
}
} finally {
if (this.deep) {
traverse(value)
}
popTarget()
this.cleanupDeps()
}
return value
}
} // 渲染watcher获取 获取回调 updateComponent = () => {vm._update(vm._render(), hydrating)} 执行
/* src/core/instance/render.js */
7.Vue.prototype._render = function (): VNode {
vnode = render.call(vm._renderProxy, vm.$createElement)
} // 执行render(h){ return h('my') }h为$createElement方法创建vnode
/* src/core/vdom/create-element.js */
8.export function createElement (
context: Component,
tag: any,
data: any,
children: any,
normalizationType: any,
alwaysNormalize: boolean
): VNode | Array<VNode> {
return _createElement(context, tag, data, children, normalizationType)
} // 创建vnode元素
export function _createElement (
context: Component, // vue实例
tag?: string | Class<Component> | Function | Object,
data?: VNodeData,
children?: any,
normalizationType?: number
): VNode | Array<VNode> {
let Ctor
if (typeof tag === 'string') {
else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) // 获取全局组件绑定在vue函数上的全局组件
{
// component
vnode = createComponent(Ctor, data, context, children, tag) // 创建vnode
}
}
}// 创建Ctor和vnode元素
/* src/core/vdom/create-component.js */
9.export function createComponent (
Ctor: Class<Component> | Function | Object | void, // 子类my 合并了vue上的¥options
data: ?VNodeData,
context: Component, // vue实例对象
children: ?Array<VNode>,
tag?: string
): VNode | Array<VNode> | void {
const baseCtor = context.$options._base //_base等于vue函数 Vue (options) {this._init(options)}
// extract props
const propsData = extractPropsFromVNodeData(data, Ctor, tag)
const listeners = data.on
// replace with listeners with .native modifier
// so it gets processed during parent component patch.
data.on = data.nativeOn
// install component management hooks onto the placeholder node
installComponentHooks(data)
// 创建一个包裹住my组件的父容器组件 vue-component-1-my
const vnode = new VNode(
`vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
data, undefined, undefined, undefined, context,
{ Ctor, propsData, listeners, tag, children },
asyncFactory
)
else if (isDef(vnode)) {
if (isDef(ns)) applyNS(vnode, ns)
if (isDef(data)) registerDeepBindings(data)
return vnode
}
} // 创建包裹my子组件的父组件vue-component-1-my的vnode元素
// 查看图1 返回第7步
/* src/core/instance/render.js */
10.Vue.prototype._render = function (): VNode {
return vnode
} // 返回vue-component-1-my vnode
// 返回第5步 updateComponent
/* src/core/instance/lifecycle.js */
11.Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
const vm: Component = this // 这个vm应为vue创建的的实例对象
if (!prevVnode) {
// initial render
vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)
} // 更新页面
}
/* src/core/vdom/patch.js */
12. return function patch (oldVnode, vnode, hydrating, removeOnly) {
const isRealElement = isDef(oldVnode.nodeType)
if (isRealElement) {
oldVnode = emptyNodeAt(oldVnode) // oldVnode = #app元素赋值
}
// create new node
createElm(
vnode,
insertedVnodeQueue,
// extremely rare edge case: do not insert if old element is in a
// leaving transition. Only happens when combining transition +
// keep-alive + HOCs. (#4590)
oldElm._leaveCb ? null : parentElm,
nodeOps.nextSibling(oldElm)
)
}
function createElm (
vnode, // vue-component-1-my
insertedVnodeQueue, // []
parentElm, // body dom元素
refElm,
nested,
ownerArray,
index
) {
if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
return
}
}
function createComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
if (isDef(i = i.hook) && isDef(i = i.init)) {
i(vnode, false /* hydrating */)
}// 执行组件 hooks生命周期 (init,prepatch,insert,destroy)中的init
}
/* src/core/vdom/create-component.js */
13.const componentVNodeHooks = {
init (vnode: VNodeWithData, hydrating: boolean): ?boolean {
else {
const child = vnode.componentInstance = createComponentInstanceForVnode(
vnode,
activeInstance
)
child.$mount(hydrating ? vnode.elm : undefined, hydrating)
}
},
}
export function createComponentInstanceForVnode (
vnode: any,
parent: any,
): Component {
const options: InternalComponentOptions = {
_isComponent: true,
_parentVnode: vnode,
parent
}
// check inline-template render functions
const inlineTemplate = vnode.data.inlineTemplate
return new vnode.componentOptions.Ctor(options)
} // 执行全局组件my的this._init(options)方法
// 返回(一)创建全局组件 第2步 查看图二options参数的值
// 再次执行(二)创建vue对象 第2步 执行完后回到第13步
child.$mount(hydrating ? vnode.elm : undefined, hydrating)
// 再次执行4、5、6步后 返回第12步
// 其中第五步vm._update(vm._render(), hydrating)
// vm._render()返回my组件的vnode
// vm._update执行最终页面dom渲染
/* src/core/instance/lifecycle.js */
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
const vm: Component = this
if (!prevVnode) {
// initial render
vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)
} else {
// updates
vm.$el = vm.__patch__(prevVnode, vnode)
}
restoreActiveInstance()
if (prevEl) {
prevEl.__vue__ = null
}
if (vm.$el) {
vm.$el.__vue__ = vm
}
// if parent is an HOC, update its $el as well
if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
vm.$parent.$el = vm.$el
}
} // 执行__patch__ 更新页面 将最终真实#app 下render函数中的
// 内容转换为真实dom赋值给vm.$el
/* src/core/vdom/patch.js */
14.return function patch (oldVnode, vnode, hydrating, removeOnly) {
createElm(vnode, insertedVnodeQueue)
return vnode.elm
}
function createElm (
vnode,
insertedVnodeQueue,
parentElm,
refElm,
nested,
ownerArray,
index
) {
// ...
vnode.elm = vnode.ns
? nodeOps.createElementNS(vnode.ns, tag)
: nodeOps.createElement(tag, vnode) // 创建my组件 vnode中的elm属性 = dom元素
createChildren(vnode, children, insertedVnodeQueue) // 递归创建my组件中的子元素标签(已转换为vnode)
insert(parentElm, vnode.elm, refElm) // 递归插入到子元素的父级elm中
}// 将my组件嵌套的vode中的elm创建出来
// 返回到patch return vnode.elm
// 返回到第13步_update
// 返回到6步 value = this.getter.call(vm, vm)
// 返回到第5步 mountComponent
// 返回到第4步 runtime/index.js Vue.prototype.$mount
// 返回到第3步 entry-runtime-with-compiler.js Vue.prototype.$mount
// 返回到第13步 componentVNodeHooks
// 返回到第9步 vdom/create-component.js createComponent
function initComponent (vnode, insertedVnodeQueue) {
if (isDef(vnode.data.pendingInsert)) {
insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert)
vnode.data.pendingInsert = null
}
vnode.elm = vnode.componentInstance.$el
if (isPatchable(vnode)) {
invokeCreateHooks(vnode, insertedVnodeQueue)
setScope(vnode)
} else {
registerRef(vnode)
insertedVnodeQueue.push(vnode)
}
} // 将组件elm插入页面中
// 返回第12步 createElm
// 流程结束
评论 (0)