阅读 126

源码看vue中对标签和组件渲染区别

最近一有时间还是会研究研究vue源码,虽然现在还有很多地方不懂,但是还是要把搞懂的记录下,今天主要写写vue中对标签和对组件渲染的区别

runtime-only原理

区别于runtime-compiler模式(见我上一篇文档),runtime-only模式基于webpack中vue-loader生成的render函数,直接走 render => vdome => patch流程

plantform/runtime/index

    Vue.prototype.__patch__ = inBrowser ? patch : noop  // 定义在浏览器环境下patch     Vue.prototype.$mount = function ( // 在runtimeonly版本中并没有用到         el?: string | Element,         hydrating?: boolean    ): Component {         el = el && inBrowser ? query(el) : undefined         return mountComponent(this, el, hydrating)  //   }      复制代码

我们一般在main.js中写的$mount方法即是上面的方法

new Vue({ render: h => h(App) }).$mount('#app') 复制代码

继续看下mountComponent,其在core/instance/lifecycle.js,在这里先基于render生成vnode, 然后在update方法中进行patch

    export function mountComponent (         vm: Component,         el: ?Element,         hydrating?: boolean     ): Component {         vm.$el = el          updateComponent = () => {         const vnode = vm._render() // 这里调用createElement方法,生产vdom         vm._update(vnode, hydrating) // 这里将vdom对象渲染到页面 } 复制代码

render函数

core/instance/render.js中,render方法实质上是是调用了createElement方法,在该方法中,假如识别是组件,则调用createComponent实现转vnode

对于createComponent方法

export function createComponent (     Ctor: Class<Component> | Function | Object | void,     data: ?VNodeData,     context: Component,     children: ?Array<VNode>,     tag?: string ): VNode | Array<VNode> | void {     if (isUndef(Ctor)) {     return } const baseCtor = context.$options._base // 基于Vue创建子组件构造器,baseCtor即是Vue if (isObject(Ctor)) {     Ctor = baseCtor.extend(Ctor) } // 组装组件钩子 installComponentHooks(data) // 生成组件对应的vnode const vnode = new VNode(     `vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,     data, undefined, undefined, undefined, context,     { Ctor, propsData, listeners, tag, children },     asyncFactory ) return vnode 复制代码

createComponent做了三件事,生成构造器;组装组件钩子;生产对应的vnode

_update方法

    Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {         const vm: Component = this         const prevEl = vm.$el         const prevVnode = vm._vnode         const restoreActiveInstance = setActiveInstance(vm)         vm._vnode = vnode         if (!prevVnode) {                 // 基于patch实现               vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */) } else {         vm.$el = vm.__patch__(prevVnode, vnode) } 复制代码

patch方法在core/vdom/patch.js中,基于createPatchFunction方法返回patch方法

其中patch方法,主要由createElm实现

    if (isDef(vnode.elm) && isDef(ownerArray)) {     vnode = ownerArray[index] = cloneVNode(vnode) }     vnode.isRootInsert = !nested // for transition enter check     // 假如是组件,则返回true,进入createComponent中     if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {         return     }     // 后续对非组件元素进行patch     ...  } 复制代码

对于在patch中的createComponent

    function createComponent (vnode, insertedVnodeQueue, parentElm, refElm) {         let i = vnode.data         if (isDef(i)) {             const isReactivated = isDef(vnode.componentInstance) && i.keepAlive             if (isDef(i = i.hook) && isDef(i = i.init)) {                 // 执行组件init钩子,                 i(vnode, false /* hydrating */)}             if (isDef(vnode.componentInstance)) {                 // 初始化子组件                 initComponent(vnode, insertedVnodeQueue)                 // 将自组件插入父组件中                 insert(parentElm, vnode.elm, refElm)                 if (isTrue(isReactivated)) {                         reactivateComponent(vnode, insertedVnodeQueue, parentElm, refElm)                    }         return true } } }      复制代码

最后,在网上找到一张关于父子组件渲染关系图

image.png


作者:湾里晴空
链接:https://juejin.cn/post/7020040347870822408


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐