Vue 2.0源码分析-渲染函数render

Vue 的 _render 方法是实例的一个私有方法,它用来把实例渲染成一个虚拟 Node。它的定义在 src/core/instance/render.js 文件中:

TypeScript 复制代码
Vue.prototype._render = function (): VNode {
    const vm: Component = this
    const { render, _parentVnode } = vm.$options

    // reset _rendered flag on slots for duplicate slot check
    if (process.env.NODE_ENV !== 'production') {
        for (const key in vm.$slots) {
            // $flow-disable-line
            vm.$slots[key]._rendered = false
        }
    }

    if (_parentVnode) {
        vm.$scopedSlots = _parentVnode.data.scopedSlots || emptyObject
    }

    // set parent vnode. this allows render functions to have access
    // to the data on the placeholder node.
    vm.$vnode = _parentVnode
    // render self
    let vnode
    try {
        vnode = render.call(vm._renderProxy, vm.$createElement)
    } catch (e) {
        handleError(e, vm, `render`)

        // return error render result,
        // or previous vnode to prevent render error causing blank component
        // istanbul ignore else

        if (process.env.NODE_ENV !== 'production') {
            if (vm.$options.renderError) {
                try {
                    vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)
                } catch (e) {
                    handleError(e, vm, `renderError`)
                    vnode = vm._vnode
                }
            } else {
                vnode = vm._vnode
            }
        } else {
            vnode = vm._vnode
        }
    }
    // return empty vnode in case the render function errored out
    if (!(vnode instanceof VNode)) {
        if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) {
            warn(
                'Multiple root nodes returned from render function. Render function ' +
                'should return a single root node.',
                vm
            )
        }
        vnode = createEmptyVNode()
    }
    // set parent
    vnode.parent = _parentVnode
    return vnode
}

这段代码最关键的是 render 方法的调用,我们在平时的开发工作中手写 render 方法的场景比较少,而写的比较多的是 template 模板,在之前的 mounted 方法的实现中,会把 template 编译成 render 方法,但这个编译过程是非常复杂的,之后会专门有一个章节来分析 Vue 的编译过程。

在 Vue 的官方文档中介绍了 render 函数的第一个参数是 createElement,那么结合之前的例子:

html 复制代码
<div id="app">
    {{ message }}
</div>

相当于我们编写如下 render 函数:

javascript 复制代码
render: function (createElement) {
    return createElement('div', {
        attrs: {
            id: 'app'
        },
    }, this.message)
}

再回到 _render 函数中的 render 方法的调用:

javascript 复制代码
vnode = render.call(vm._renderProxy, vm.$createElement)

可以看到,render 函数中的 createElement 方法就是 vm.$createElement 方法:

javascript 复制代码
export function initRender(vm: Component) {
    // bind the createElement fn to this instance
    // so that we get proper render context inside it.
    // args order: tag, data, children, normalizationType, alwaysNormalize
    // internal version is used by render functions compiled from templates
    vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
    // normalization is always applied for the public version, used in
    // user-written render functions.
    vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
}

实际上,vm.createElement 方法定义是在执行 initRender 方法的时候,可以看到除了 vm.createElement 方法,还有一个 vm._c 方法,它是被模板编译成的 render 函数使用,而 vm.$createElement 是用户手写 render 方法使用的, 这俩个方法支持的参数相同,并且内部都调用了 createElement 方法。

总结

vm._render 最终是通过执行 createElement 方法并返回的是 vnode,它是一个虚拟 Node。Vue 2.0 相比 Vue 1.0 最大的升级就是利用了 Virtual DOM。因此在分析 createElement 的实现前,需要先了解一下 Virtual DOM 的概念。

相关推荐
小羊没烦恼!9 小时前
T-SQL查询进阶--理解SQL SERVER中的分区表
服务器·开发语言·前端·javascript·html
Highcharts.js9 小时前
AI图表开发工具Highcharts Assist|自然语言生成图表代码
javascript·人工智能·highcharts·开发神器
志尊宝10 小时前
Vue3 零基础每日笔记(087):Vue3 高频面试题(下)
前端·javascript·vue.js·笔记·ecmascript·#vue.js
const_qiu12 小时前
第二章 2.6:初始化 NestJS 服务端 —— TypeScript 后端框架体验
前端·javascript·typescript
miofly12 小时前
GitHub 今日推荐|sweety-handdraw-video:文章转手绘口播视频
javascript·开源·github
用户831348593069813 小时前
Vue3 事件:常用用法与开发高频坑点
前端·javascript·vue.js
漫步人生走在路上14 小时前
用小语种SEO突破外贸B2B天花板:法语、德语市场的实测数据
开发语言·前端·javascript·人工智能·搜索引擎·ecmascript
ydjs678899-bot15 小时前
您的Next.js中间件匹配器配置可能会跳过您认为它保护的路由
开发语言·javascript·中间件
Chengbei1115 小时前
JsOwl|AI 赋能 JS 敏感信息扫描器,AST + 正则、source‑map 源码还原、登录态爬虫输出交互式 HTML 报告
开发语言·javascript·网络·人工智能·爬虫·网络安全·自动化
ShineWinsu16 小时前
对于JavaScript:初识JavaScript以及输入输出
java·开发语言·前端·javascript·css·面试·html