Vue2源码梳理:render函数的实现

HWUI源码剖析(一) - 渲染中RenderProxy视角看一种很有用的编程模式 实际的工程项目中,往往都是多线程编程,也就是必然有某些业务逻辑或者功能要运行在特定的线程,比如android开发中常见的IO线程,UI线程,Render线程,这样会涉及从线程A向这些工作线程通信或者函数调用的代码编程,具体实现上可以有多种多样,但是他们的核心思想其实都是一致的,Android Handler/Looper视角看UI线程的原理_nginux的博客-优快云博客。 阅读详情

render

  • 在 $mount 时,会调用 render 方法
  • 在写 template 时,最终也会转换成 render 方法
  • Vue 的 _render 方法是实例的一个私有方法,它用来把实例渲染成一个虚拟 Node
  • 它的定义在 src/core/instance/render.js 文件中,它返回的是一个vnode
  • 这里看下它的实现
    Vue.prototype._render = function (): VNode {
      const vm: Component = this
      // 从 $options 中拿到这个 render 函数
      // 这个 render 函数, 可以是用户自己写,也可以通过编译生成
      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 {
        
        // call的第一个参数是当前上下文, vm._renderProxy 在生产环境下,就是 VM,也就是this本身, 在开发环境它可能是一个proxy对象  
        // 这个 vm.$createElement 也是一个函数,会在下面来说
        // 总体来说就是生成 vnode
        vnode = render.call(vm._renderProxy, vm.$createElement)
      } catch (e) {
        // 捕获并处理错误,尝试再次生成 vnode
        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)) {
        // 如果拿到的 vnode 是个数组,说明模板有多个根节点,这个在后续vue3中支持,在vue2中会报下面的警告
        // 在vue2 中 vnode 是一个 vdom, 
        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
    }
    
    • 注意,上面的 vm.$createElement 在 initRender 函数中被初始化定义
    • 而 initRender 是在一开始 new Vue 的时候,会调用 _init 函数中被执行
      // initRender 函数中
      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)
      
      • 看到上面两个函数区别,就是最后一个参数不一样
      • _c 这个函数它实际上是被编译生成的render函数所使用的一个方法
      • $createElement 是给我们手写render函数提供了一个创建vnode的一个方法
        var app = new Vue({
            el: '#app',
            // 手写 render 函数
            render(createElement) {
              return createElement('div', {
                attrs: {
                  id: 'app2' // 这些写后,这里挂载的 div 元素,会替换掉之前的 #app 容器
                }
              }, this.message)
            },
            data() {
              return {
                message: 'Hello'
              }
            }
        })
        
        • 这里,使用render和在html中写是不一样的,它没有一个把从差值变换的这个过程
        • 之前的写法是在HTML里面定义了这个差值
          // 之前的写法
          <div id="app">
            {{ message }}
          </div>
          
        • 它在不执行vue的时候,它会先把这个东西渲染出来
        • 然后在new vue之后, 执行 mount 的时候,再把它从差值的那个message给替换成真实的数据
        • 在这里是通过纯 render 函数,当它执行完毕以后,直接挂载到页面上,这样的话体验会更好一点
        • 因为这里手写了 render 函数,所以, 整个渲染流程中,就不会再执行把 template 转换 render 函数那一步了
        • 所以就相当于直接就达到了一样的效果
    • vm._renderProxy 的定义,也是发生在 src/core/instance/init.js 中
    • 在 _init 函数中,有一个判断
      /* istanbul ignore else */
      if (process.env.NODE_ENV !== 'production') {
        initProxy(vm)
      } else {
        vm._renderProxy = vm
      }
      
      • 当前如果说是生产环境,vm._renderProxy = vm
      • 开发阶段开发阶段,则执行 initProxy(vm) 定义在 src/core/instance/proxy.js 中
        // 报错提示函数
        const warnNonPresent = (target, key) => {
          warn(
            `Property or method "${key}" is not defined on the instance but ` +
            'referenced during render. Make sure that this property is reactive, ' +
            'either in the data option, or for class-based components, by ' +
            'initializing the property. ' +
            'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.',
            target
          )
        }
        // 
        const hasHandler = {
          has (target, key) {
            const has = key in target
            const isAllowed = allowedGlobals(key) || (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data)) // 全局方法或者私有方法,或不在$data中
            // 属性不在 target 下,并且不被允许,则报错提示,比如:使用了 一个没有在 data 中定义的变量,就会报错
            if (!has && !isAllowed) {
              if (key in target.$data) warnReservedPrefix(target, key)
              else warnNonPresent(target, key)
            }
            return has || !isAllowed
          }
        }
        
        // 判断当前浏览器是否支持 proxy,Proxy作用是对对象的访问做一个劫持
        const hasProxy = typeof Proxy !== 'undefined' && isNative(Proxy)
        
        initProxy = function initProxy (vm) {
          if (hasProxy) {
            // determine which proxy handler to use
            const options = vm.$options
            const handlers = options.render && options.render._withStripped
              ? getHandler
              : hasHandler
            vm._renderProxy = new Proxy(vm, handlers) // 在这里 handlers 是 hasHandler
          } else {
            vm._renderProxy = vm
          }
        }
        
      • 这里可以看到,支持 Proxy 则 vm._renderProxy = new Proxy(vm, handlers)
  • 通过以上分析可知,vm._render 最终是通过执行 createElement 方法并返回的是 vnode
  • 而返回的vnode 它是一个虚拟 Node
vue2&&vue3--render函数(h) 此更改不会影响<template>用户。h现在是全局导入,而不是作为参数传递给渲染函数更改渲染函数参数,使其在有状态组件和函数组件的表现更加一致VNode 现在有一个扁平的 prop 结构请继续阅读来获取更多信息! 阅读详情

相关推荐

Vue2中的render函数

我们在给子组件传递数据的时候,也就是父传子,一般写在props中, 其实也可以写在attrs中,如果写在attrs中,我们也可以在子组件中props中接受attrs中的变量,如果props中没写的变量都会在attrs中,我们在组件中通过this.$attrs中可以拿到。先使用render函数封装一个组件,注意写了render函数就不要写template了,不然render函数不起作用。这是加载组件G1,注意:我们加载的组件一定是引入、注册之后的,我这里全局注册了,来创建你的 HTML。

专注于技术,分享实战经验,探索技术边界,用代码构建更美的数字世界。 1294

vue2的render函数详解

render函数和template一样,都是用来创建html模板的,但是有些场景里使用template实现起来会使代码冗余且复杂,因此产生了render函数。

如果相遇,那么你好哦~ 4129

STM32异常与中断过程详解

1. 异常与中断概念引入 异常主要是指来自CPU内部的意外事件,比如执行了未定义指令、算术溢出、除零运算等发生在CPU内部的意外事件,这些异常的发生,会引起CPU运行相应的异常处理程序;中断一般来自硬件(如片上外设、外部I/O输入等)发生的事件,当这些硬件产生中断信号时,CPU会暂停当前运行的程序,转而去处理相关硬件的中断服务程序。但无论是异常还是中断,都会引起程序执行偏离正常的流程,转而去执行异常/中断的处理函数。 下面对异常和中断的介绍,如果中断信号的产生原因来自CPU内部,则称之为异常;如果中断信号来

luobeihai的博客 1万+

vue2的render函数你用过吗?

前提 在日常使用vue2开发的过程中,我们大多是使用文档推崇的模版语法的方式进行界面HTML结构的编写 但其实在vue文档中还介绍了另外一个编写HTML的方式:render函数(渲染函数) 由于render函数更接近vue的渲染器底层,所以它具备更好的灵活性, 同时也由于贴近底层,导致写出的代码具备可读性较差,维护难度大的特点。 看完本篇可以学到什么 render函数在vue中何处调用 render函数的使用方式 为什么需要写render函数 vue2中的render函数 接下来我们讨论的主要是vue2

军火库 6415

RK3588多路MIPI摄像头采集与WiFi低延迟传输实战指南

本文详细介绍了基于RK3588平台实现多路MIPI摄像头同步采集并通过WiFi进行低延迟传输的完整实战方案。文章深入剖析了从V4L2驱动配置、多线程采集、环形缓冲区设计到UDP网络传输优化的核心技术,旨在帮助开发者在工业检测、智能安防等场景下构建高并发、高实时性的视频流系统,实现端到端延迟控制在100毫秒以内的目标。

tensor9flow的博客 788

完整内、外期货量化交易系统源码可售

支持客户登录校验,支持所有的实时行情和汇总报价功能、实时资讯(报价,列表,分时,分钟成交明晰,),多线程支持盘后收盘作业下载(日线,5分钟线,15分钟, 30分钟,60分钟线,),支持从服务器下载相关运行配置(来自服务器动态配置信息,如收盘日期等),实现状态条显示。收盘作业包括日线、5分钟线、15分钟线、30分钟、60分钟线、2小时线、4小时线每日分时走势。综合信息栏显示用户账户信息、合约信息、当日委托单记录、当日成交记录、当日平仓记录、当日跟单记录、当日(月/周)排行榜、下单栏、持仓信息;

qq_35600909的博客 1805

vue 中render执行流程梳理

用了多年vue 今天对自己了解的render 做一个梳理 一、使用template模板 先从vue 初始化开始: 众所周知项目的main.js中定义了 var app = new Vue({})这vue初始化操作 其实他会执行到 这个方法中的_init函数,在这个方法执行一些列的初始化后,判断$options是否定义el,如果定义调用 vm.$mount(vm.$options.el)函数,...

奔跑的痕迹的博客 1837

基于工作流的低代码AI应用开发:Flock平台核心架构与实战指南

在AI应用开发领域,工作流编排正成为连接大语言模型(LLM)能力与复杂业务逻辑的关键技术。其核心原理是将任务分解为模块化节点,通过可视化方式定义执行顺序与数据流向,从而实现灵活可控的自动化流程。这种范式极大地提升了开发效率,降低了技术门槛,使得开发者能够聚焦于业务设计而非底层代码。在技术价值层面,工作流编排支持检索增强生成(RAG)、多智能体协作等高级模式,并能通过人工干预节点确保关键流程的可靠性与合规性。其典型应用场景包括智能客服、自动化办公、数据分析助手等。本文以Flock平台为例,深入解析了如何利用其

weixin_26848497的博客 384

vue render函数_Vue源码中compiler部分逻辑梳理(内有彩蛋)

【小宅按】 Vue compiler部分逻辑梳理示例代码托管在:http://www.github.com/dashnowords/blogs一. 简述compiler模块Vue框架中用于模板编译的,它的作用就是将Vue中的组件模板转换成render函数,render函数在运行时可以生成虚拟节点vnode,它是Vue中虚拟DOM树的基本实现流程。完整版的Vue是包含runtime和compiler...

weixin_39604598的博客 217

【DRAM存储器五十六】LPDDR5介绍--WCK2CK Leveling和Read gate training

简述LPDDR5 WCK2CK leveling和read gate traning基本原理与操作步骤

highman110的博客 8795

用Python爬取政府采购信息的实战全流程

以 Playwright 自动采集政府采购信息结构化存储与查询可拓展关键词过滤与通知机制。

2201_76125261的博客 1150

Vue之render函数生成细节

前言 上篇文章分析了Vue中render函数的构建以及调用过程,在整体上梳理了构建出render以及调用的逻辑。知其然也知其所以然,本文就主要分析html -> vnode的过程。

玉案轩窗的博客 3169

《QGIS快速入门与应用基础》【专栏完整目录】

《QGIS快速入门与应用基础》第一卷专栏完整目录,覆盖 001–328 全部篇目与附录,逐篇可跳转。

LuckyHanMo的博客 1303

Vue2源码梳理:关于vm.$mount的实现

1 ) 在含有 compiler 版本中,先对 el 做一些处理2 ) 在没有定义 render 函数的时候,尝试获取一下 render 函数也就是说,把整个template通过一系列的逻辑判断,也是因为它支持很多很多种写法可以直接写 template也可以直接 template 是个dom对象如果不写 templete 的话,通过 el 的 outHTML 来获取这个 templete把这个template 通过这个编译的手段也转化成这个render函数。

Wang的专栏 1764

解决pd.read_json报错ValueError: Trailing data问题

首先,我们使用open函数打开JSON文件,然后使用json.load函数将JSON文件数据解码为Python对象。在使用Python进行数据处理中,我们经常需要将JSON格式的数据读入到DataFrame中进行处理。而使用pandas库的read_json函数,就可以方便地将JSON数据读入到DataFrame中。但是有时候在读取JSON数据时,会遇到一个非常常见的错误:ValueError: Trailing data。这个错误的解决方案并不难,只需要在read_json中添加一个参数即可。

学习使你进步。 2234

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Vue之render构建、调用整体流程

前言 本篇文章是想要探寻下Vue中是如何处理html到vnode以及vnode转换为html的过程,主要是梳理其大概流程,一些细节流程会在单独文章的细究。

玉案轩窗的博客 3661

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

【手写 Vue2.x 源码】第十六篇 - 生成 render 函数 - 代码拼接

本篇,主要介绍了生成 render 函数 - 代码拼接:1,render 函数的分析和实现方案;2,拼接 render 函数结构:generate(ast);3,处理属性及属性值中的样式:genProps(ast.attrs);4,递归处理儿子:genChildren(el);5,对文本和变量进行包装处理,详细分析文本处理流程;

BraveWangDev 842

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

【Vue高级知识】梳理Vue源码的整个实现流程

Vue的整个实现流程源码解读???(总结点) 解析模板成render函数 <template></template> --->>> render 函数 with函数的使用 模板中的所有信息都被render函数包含 模板中用到的data中的属性,都变成了JS变量 模板中的v-model v-for v-on都变成了JS逻辑 render函数返回v...

小牛itbull的博客 444

Vue2源码梳理:update的整体实现流程

回到之间 $mount时,mountComponent 函数的过程,vm._render 是如何创建了一个 VNode,接下来就是要把这个 VNode 渲染成一个真实的 DOM 并渲染出来,这个过程是通过 vm._update 完成的,_update 它是一个vue 的私有方法,它把我们的 vnode 渲染成真实的 dom,_update的方法,也是原型上的一个方法, 它的定义在src/core/instance/lifecycle.js 中

Wang的专栏 2308

Vue源码中compiler部分逻辑梳理(内有彩蛋)

【摘要】 Vue compiler部分逻辑梳理 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 简述 compiler模块Vue框架中用于模板编译的,它的作用就是将Vue中的组件模板转换成render函数,render函数在运行时可以生成虚拟节点vnode,它是Vue中虚拟DOM树的基本实现流程。完整版的Vue是包含runtime和com...

华为云官方博客 1476

Vue实例之render构建+调用

前言 前几篇文章分析了Vue初始化以及Vue实例创建时data、computed、$mount相关的处理,引出了Vue响应式原理的实现以及computed与data不同的处理。 本篇文章是想要探寻下Vue中是如何处理html到vnode以及vnode转换为html的过程,之后会结合Moon.js中关于此过程的处理,比较二者的区别。 而这篇文章的初衷是想要结合此处的实现逻辑,自实现下简易的MV...

細水、長流√的专栏 605

Vue3源码梳理:关于运行时和编译时

上述 v-if 和 m-com 自定义组件不是正常的html, 浏览器是不认识的,所以不会解析。.vue文件是单文件组件, 在template中写入的html是真实的html标记节点么?vue中的编译时,准确来说是编译器的意思,核心代码在 compiler-core模块下。运行时做不到的事情,通过html标签结构的方式来渲染解析成真实的dom节点。初次渲染,会生成一个ul标签,同时生成三个li标签,并把他们挂载到div中。这个过程主要是:让假标记,被渲染成真实的html标签,最终呈现给用户。

Wang的专栏 990

Vue2源码梳理:vdom结构与createElement的实现

浏览器原生dom对象,本身就是一个非常复杂的对象,单单把 div 这个dom对象拿出来,遍历它的属性,将是一个庞大的存在,因为浏览器的标准就是把这个dom设计的非常复杂,所以当我们去频繁的操作dom的话,一定会有一些性能问题,vdom(Virtual DOM), 其实就是用一个原生的js对象去描述一个dom节点,它的创建比创建一个真实的dom的代价要小很多,在vue.js中的 vdom 的定义在 src/core/vdom/vnode.js

Wang的专栏 1426

Vue3源码梳理:运行时的设计方案概况

在运行时 runtime ,渲染器 renderer 会遍历整个虚拟dom树,并据此结构构建真实的dom树这个过程我们可以把它叫做挂载 mount在这个 vnode 对象发生变化时候,我们会对比 旧的 VNode 和 新的 VNode 之间的区别找出它们之间的区别,并应用这其中的变化到真实的dom上,这个过程叫做更新 patch。

Wang的专栏 313

Vue源码学习2--$mount的执行流程

主要梳理了一下$mount的执行和构建过程。文章重点有两块:1、公共的 $mount 方法的创建,2、带编译模板的 vue 给 $mount 扩展了编译部分。 上次梳理了vue入口文件的怎么查找,这次看一看$mount。由于后面尚未学习,只简单梳理流程。 1、扩展$mount 首先打开entry-runtime-with-compiler.js文件,这里我们可以看到对$mount的扩展: 先用 mount 变量存储Vue.prototype.$mount备用,接着重新给Vue.prototype.$m.

ccattempt的博客 792

【Vue2.0源码学习】模板编译篇-模板解析阶段(总结)

到现在,模板编译的三大阶段就已经全部介绍完毕了,接下来本篇文章,就以宏观角度回顾并梳理一下模板编译整个流程是怎样的。首先,我们需要搞清楚模板编译的最终目的是什么,它的最终目的就是:把用户所写的模板转化成供Vue实例在挂载时可调用的render函数。或者你可以这样简单的理解为:模板编译就是一台机器,给它输入模板字符串,它就输出对应的render函数。我们把模板编译的最终目的只要牢记在心以后,那么模板编译中间的所有的变化都是在为达到这个目的而努力。接下来我们就以宏观角度来梳理一下模板编译的整个流程。

一个前端开发者 521
上一篇: Vue2源码梳理:关于vm.$mount的实现
下一篇: Vue2源码梳理:vdom结构与createElement的实现
Wang's Blog
博客等级 码龄12年 7434粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值