vue create()获取ref_Vue视图渲染原理解析,从构建VNode到生成真实节点树

本文深入解析Vue的视图渲染过程,从`create()`获取`ref`开始,涵盖组件的`$mount`挂载、`_render`构建VNode、`createElement`生成虚拟DOM及`_update`更新真实DOM和`patch`的DOM差异对比等关键步骤。
摘要由CSDN通过智能技术生成

前言

在 Vue 核心中除了响应式原理外,视图渲染也是重中之重。我们都知道每次更新数据,都会走视图渲染的逻辑,而这当中牵扯的逻辑也是十分繁琐。 本文主要解析的是初始化视图渲染流程,你将会了解到从挂载组件开始, Vue 是如何构建 VNode ,又是如何将 VNode 转为真实节点并挂载到页面。

挂载组件($mount)

Vue 是一个构造函数,通过 new 关键字进行实例化。
// src/core/instance/index.jsfunction Vue (options) {
    if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}
在实例化时,会调用 _init 进行初始化。
// src/core/instance/init.js
Vue.prototype._init = function (options?: Object) {
    const vm: Component = this
    // ...if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }
_init 内会调用 来挂载组件,而mount 方法实际调用的是 mountComponent 。
// src/core/instance/lifecycle.jsexport function mountComponent (
  vm: Component,
  el: ?Element,
  hydrating?: boolean
): Component {
  vm.$el = el
  // ...
  callHook(vm, 'beforeMount')let updateComponent
  /* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
    // ...
  } else {
    updateComponent = () => {
      vm._update(vm._render(), hydrating)  // 渲染页面函数
    }
  }
  // we set this to vm._watcher inside the watcher's constructor
  // since the watcher's initial patch may call $forceUpdate (e.g. inside child
  // component's mounted hook), which relies on vm._watcher being already defined
  new Watcher(vm, updateComponent, noop, { //  渲染watcher
    before () {
      if (vm._isMounted && !vm._isDestroyed) {
        callHook(vm, 'beforeUpdate')
      }
    }
  }, true /* isRenderWatcher */)
  hydrating = false
  // manually mounted instance, call mounted on self
  // mounted is called for render-created child components in its inserted hook
  if (vm.$vnode == null) {
    vm._isMounted = true
    callHook(vm, 'mounted')
  }
  return vm
}
mountComponent 除了调用一些生命周期的钩子函数外,最主要是 updateComponent ,它就是负责渲染视图的核心方法,其只有一行核心代码:
vm._update(vm._render(), hydrating)
vm._render 创建并返回 VNode , vm._update 接受 VNode 将其转为真实节点。 updateComponent 会被传入 渲染Watcher ,每当数据变化触发 Watcher 更新就会执行该函数,重新渲染视图。updateComponent 在传入 渲染Watcher 后会被执行一次进行初始化页面渲染。 所以我们着重分析的是 vm._render 和 vm._update 两个方法,这也是本文主要了解的原理—— Vue 视图渲染流程。

构建VNode(_render)

首先是 _render 方法,它用来构建组件的 VNode 。
// src/core/instance/render.js
Vue.prototype._render = function () {
    const { render, _parentVnode } = vm.$options
    vnode = render.call(vm._renderProxy, vm.$createElement)return vnode
}
_render 内部会执行 render 方法并返回构建好的 VNode 。render 一般是模板编译后生成的方法,也有可能是用户自定义。
// src/core/instance/render.jsexport function initRender (vm) {
    
    vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
    vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
}
initRender 在初始化就会执行为实例上绑定两个方法,分别是 vm._c 和 vm.$createElement 。它们两者都是调用 createElement 方法,它是创建 VNode 的核心方法,最后一个参数用于区别是否为用户自定义。 vm._c 应用场景是在编译生成的 render 函数中调用, vm.createElement ,我们在自定义 render 函数接收到的参数就是它。

createElement

// src/core/vdom/create-elemenet.jsexport function createElement (
  context: Component,
  tag: any,
  data: any,
  children: any,
  normalizationType: any,
  alwaysNormalize: boolean
): VNode | Array { if (Array.isArray(data) || isPrimitive(data)) {
    normalizationType = children
    children = data
    data = undefined
  }if (isTrue(alwaysNormalize)) {
    normalizationType = ALWAYS_NORMALIZE
  }return _createElement(context, tag, data, children, normalizationType)
}
createElement 方法实际上是对 _createElement 方法的封装,它允许传入的参数更加灵活。
export function _createE
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值