用了多年vue 今天对自己了解的render 做一个梳理

一、使用template模板

先从vue 初始化开始:

众所周知项目的main.js中定义了

var app = new Vue({})这vue初始化操作

其实他会执行到

这个方法中的_init函数,在这个方法执行一些列的初始化后,判断$options是否定义el,如果定义调用

vm.$mount(vm.$options.el)函数,这个函数其实是在entry-runtime-with-compiler.js中定义的,if (!options.render) {}判断是否定义了render函数,如果未定义再判断是否定义template,如果定义直接调用‘compileToFunctions’函数将template编译成为一个匿名函数,这里先借一个简单案例,打个断点测试下执行流程

import Vue from 'vue'

/**
* 使用 template 方式
*/
var app = new Vue({
el:'#admin',
template:'<ul :class="bindCls" class="list" v-if="isShow">'+
'<li v-for="(item,index) in data" @click="clickItem(index)">{{item}}:{{index}}</li></ul>',
data(){
return {
bindCls:'a',
isShow:true,
data:['A','B','C','D']
}
},
methods:{
clickItem(index){
console.log(index);
}
}
})

最后render匿名函数内容是这样的

(function anonymous(
) {
with(this){return (isShow)?_c('ul',{staticClass:"list",class:bindCls},_l((data),function(item,index){return _c('li',{on:{"click":function($event){return clickItem(index)}}},[_v(_s(item)+":"+_s(index))])}),0):_e()}
})

看似一段简短的render,其实生成这个render是一个相当复杂的过程

1、将template 转换为render 字符串

首先在compiler 文件中的index.js中

定义了createCompiler常量该值为create-compiler.js里的createCompilerCreator函数,同时将baseCompile函数传入

而createCompilerCreator返回的是一个createCompiler函数而该createCompiler函数最后的返回值是一个

{ compile, compileToFunctions: createCompileToFunctionFn(compile) } 对象,


该对像中createCompileToFunctionFn其实是to-functiuon.js中定义的,目的就是把compile作为参数传入,进行一些列校验合并等

再回过头来调用compile实现编译操作,取得最后compile编译的结果,其实准确说是baseCompile编译后的结果,因compile中其实是调用baseCompile进行模板编译的(其中的通过parse 生成ast和generate生成code就不细说了,其实这个code中就包含了render),

createCompileToFunctionFn取得了编译后的render并使用createFunction将其转为一个匿名函数,就是上面看见的样子了


createCompilerCreator值返回到entry-runtime-with-compiler.js中的Vue.prototype.$mount函数中,同时将render挂载到了vu.$options上,再次调用runtime下index.js中的Vue.prototype.$mount函数

此时函数中又调用到了core/instance/lifecycle中的mountComponent函数;mountComponent函数在new Watcher中执行get(), 调用了updateComponent函数; 开始了执行vm._render()的操作,这个函数其实就定义在instance/render.js中;


这一连串的调用最终将template编译为render,又将其使用createElement编译为vdom,再使用__patch__初始化事件将其生成真实dom插入到页面的body中

看文字很不直观,这里截几个源码图来看看

2、render执行调用

好了现在就来看看render究竟是怎么执行的,其实他的执行也挺简单直接使用call进行调用,如

这个里面的_renderProxy其实是在init.js中绑定的





其实就是在开发阶段做一些校验,再将vm 使用proxy代理一个handlers将其返回,而生产环境就是vm实例

vm.$createElement是上面一个initRender中初始化了,其实这个主要是用于我们手写render用的

render.call(vm._renderProxy, vm.$createElement),中render就是上面说过的匿名函数

(function anonymous(
) {
with(this){return (isShow)?_c('ul',{staticClass:"list",class:bindCls},_l((data),function(item,index){return _c('li',{on:{"click":function($event){return clickItem(index)}}},[_v(_s(item)+":"+_s(index))])}),0):_e()}
})

他里面的with作用更改作用域链,执行时会首先从局部去查找里面的函数,如_c(),如果局部没有就会到其绑定的作用域this中去找,在render.call时我们知道其实是将vm传入了,而这个_c()就是上面initRender中定义的

,

而其他的如_e(),_l()这些就是在render-helper中了

而_c()又对应一个createElement函数这个就是真正的创建vdom的地方了,到此render 编译template就完成了

二、手写render

import Vue from 'vue'

var app = new Vue({
el:'#admin',
render(createElement){
return createElement('div',{
attrs:{
id:'admin'
}
},this.message)
},
data(){
return {
message:'Hello vue'
}
}
})

而手写render 其实是一样的,只是在entry-runtime-with-compiler.js不会进行compileToFunctions编译,而直接调用mount,而上面代码中render里的createElement是在render.call(vm._renderProxy, vm.$createElement)直接将createElement函数作为参数传入的,最后将该函数返回值返回给 Vue.prototype._update,然后将其使用vm.__patch__转为真实dom数插入到页面中

三、自定义函数进行模拟

手动写render


var vm = function(){} function createEl(a,b){
console.log(a,b);
} vm.$createEl = (a,b) => createEl(a,b); render.call(vm,vm.$createEl); // div1 div2 function render(createEl){
return createEl('div1','div2');
}

2、编译 template为render

   // vm构造函数
var vm= function(){};
// 创建vdom函数
function createEl(a,b){
console.log(a,b);
};
// 模拟获得编译后的render 字符串
var compiledRender = "with(this){return _c('div1','div2')}";
// 将其转换为函数
var render= new Function(compiledRender); // 为vm定义_c函数
vm._c = (a,b) => createEl(a,b);
// 为vm定义$createEl 函数
vm.$createEl = (a,b) => createEl(a,b); // 执行调用
render.call(vm, vm.$createEl ); // div1 div2

到此把整个render 流程理了一遍,感谢阅读有不正确处欢迎指正和探讨,学习永不止步,探索从未停止。

vue 中render执行流程梳理的更多相关文章

  1. tf中计算图 执行流程学习【转载】

    转自:https://blog.csdn.net/dcrmg/article/details/79028003 https://blog.csdn.net/qian99/article/details ...

  2. Spring启动执行流程梳理

    注:本文梳理启动流程使用的Spring版本:4.0.2.RELEASE 使用spring配置,都需要在web.xml中配置一个spring的监听器和启动参数(context-param),如下: &l ...

  3. [转]两表join的multi update语句在MySQL中的执行流程分析

    出自:http://hedengcheng.com/?p=209 两表join的multi update语句,执行结果与预计不一致的分析过程 — multi update结论在实际应用中,不要轻易使用 ...

  4. Vue中render: h => h(App)的含义

    // ES5 (function (h) { return h(App); }); // ES6 h => h(App); 官方文档 render: function (createElemen ...

  5. vue中render: h => h(App)的详细解释

    2018年06月20日 10:54:32 H-L 阅读数 5369   render: h => h(App) 是下面内容的缩写:   render: function (createEleme ...

  6. Java 中控制执行流程

    if-else 非常常用的流程控制非 if-else 莫属了,其中 else 是可选的,if 有两种使用方式 其一: if (Boolean-expression) { statement; } 其二 ...

  7. web项目中的执行流程参数传递详解

    还是从这个图开始讲解: struts2中有一个存放数据的中心:值栈.(值栈里面有map和对象栈) 首先:值栈的作用范围是一个请求:request作用域(一个请求是代表的一个过程,即页面点击到数据返回到 ...

  8. vue中beforeRouteEnter 执行的时机及运用的误区?

    beforeRouteEnter钩子 beforeRouteEnter (to, from, next) { console.log(this); //undefined,不能用this来获取vue实 ...

  9. MySQL之执行流程

    最近开始在学习mysql相关知识,自己根据学到的知识点,根据自己的理解整理分享出来,本篇文章会分析下一个sql语句在mysql中的执行流程,包括sql的查询在mysql内部会怎么流转,sql语句的更新 ...

  10. 一条SQL语句在MySQL中如何执行的

    本篇文章会分析一个 sql 语句在 MySQL 中的执行流程,包括 sql 的查询在 MySQL 内部会怎么流转,sql 语句的更新是怎么完成的. 在分析之前我会先带着你看看 MySQL 的基础架构, ...

随机推荐

  1. 基于 Agora SDK 实现 Windows 端的多人视频互动(基于3.6.2版本)

    本文介绍如何通过 Agora SDK 在 Windows 平台快速实现互动直播.互动直播和实时通话的区别就在于,直播频道的用户有角色之分.你可以将角色设置为主播或者观众,其中主播可以收.发流,观众只能 ...

  2. Maven安装详解

    Maven Maven是apache软件基金会旗下的一个开源项目,是一款用于管理和构建Java项目的工具. Maven的作用? 先来简单介绍一下Maven的作用 (1)依赖管理 方便快捷的管理项目依赖 ...

  3. 改善与提高linux系统的音质

    当初装Linux系统的时候,我就发现了,deepin和ubuntu的linux平台音质和Windows平台下的音质不一样.硬件参数没变,歌曲音频文件相同的情况下,linux播放歌曲的时候动态和音乐细节 ...

  4. .Net 6.0定义全局当前身份缓存对象

    背景: 当前身份缓存对象顾名思义就是:当前登录的用户身份对象,那它解决了什么问题呢?其实在我们日常开发过程中经常能用的到几乎是必备的,就比如我给某个表插入数据时需要创建人或者一些权限的访问,都得用到当 ...

  5. BrightlyPro - 照片视屏后期自动调色增亮工具

    BrightlyPro 自动增强您的照片和视频,你最需要它.通过一个滑块,BrightlyPro 立即使您的照片自适应地亮起来,同时保持光影之间令人愉悦的平衡,而不会扭曲已经点亮的区域. 下载 ➤ B ...

  6. MySQL 中索引是如何实现的,有哪些类型的索引,如何进行优化索引

    MySQL 中的索引 前言 索引的实现 哈希索引 全文索引 B+ 树索引 索引的分类 聚簇索引(clustered index) 非聚簇索引(non-clustered index) 联合索引 覆盖索 ...

  7. 搭建react的架手架

    1.回顾 cnpm i @vue/cli -g ----- 4的脚手架 ------ webpack 4 cnpm i @vue/cli@3 -g ----- 3的脚手架 ------ webpack ...

  8. PyQt5学习 (1)--对象的基本操作、QObject

    参考视频:[Python-GUI编程-PyQt5 (少)] https://www.bilibili.com/video/BV17J41177ro/?share_source=copy_web& ...

  9. Junit环境配置和在IDEA中使用Junit学习记录

    Junit环境配置 步骤1:检查电脑中Java环境是否配置成功 因为JUnit 是 Java 的一个框架,所以最根本的需要是在你的机器里装有 JDK. 1.1 进入cmd控制台界面,输入java/ja ...

  10. 当前标识(IIS APPPOOL\derl)没有对“C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files”的写访问权限。

    解决方法:运行cmd 执行以下指令 1.检查用户组,找到iis相关的用户组, 2.将电脑登录用户添加到该组 3.为指定的用户或用户组授予权限,使其可以访问 IIS 元数据库和 ASP.NET 使用的其 ...