学习vue源码(10)手写render渲染函数,在线前端开发学习

return ret

}

看到 renderList 接收两个参数,val 和 render,而 _l 调用的时候,也就是传入的这两个参数,比如下面

_l(2,function(item, index) {

return _c(‘span’)

})

val 就是 2,_render 就是上面的函数

1 遍历的数据 val

遍历的数据分为三种类型,一种是对象,一种是数字,一种是数组

2 单个 vnode 渲染回调 _render

重要是这个回调

1、renderList 每次遍历都会执行回调,并把的每一项 item 和 index 都传入 回调中

2、回调执行完毕,会返回 vnode

3、使用数组保存 vnode,然后 遍历完毕就返回 数组

于是可以看上面的 render 函数 ,传入了 数字2,和 创建 span 的回调

_l(2,function(item, index) {

return _c(‘span’)

})

_l 执行完毕,内部遍历两次,最后返回 两个 span vnode 的数组,然后传给外层的 _c ,作为 vnode.children 保存

render 执行完毕,得到这样的 vnode

{

tag:“div”,

data:undefined,

children:[{

tag:“span”,

data:undefined

},{

tag:“span”,

data:undefined

}]

}

都灰常简单啊,没写之前,我还觉得内容应该挺多的,写完发现还可以

当然还有其他的 render

比如要模板含有 filter,我们来看看

Filters - 源码版


下面的讲解会以下面例子 作为讲解模板

这里有一个过滤器 all,用来过滤 parentName

{{parentName|all }}

new Vue({

el:document.getElementsByTagName(“div”)[0],

data(){

return {

parentName:111

}

},

filters:{

all(){ return “我是过滤器” }

}

})

页面的 filter 解析成什么

首先,上面的例子会被解析成下面的渲染函数

(function() {

with(this) {

return _c(‘div’,[

_v(_s(_f(“all”)(parentName)))

])

}

}

这段代码继续解释下

  1. _c 是渲染组件的函数,这里会渲染出根组件

  2. 这是匿名自执行函数,后面渲染的时候调用,会 绑定当前实例为作用域

  3. with 的作用是,绑定大括号内代码的 变量访问作用域,所以里面的所有变量都会从 实例上获取

然后,你可以看到 ' parentName | all ' 被解析成 _f('all')( parentName )

怎么解析的?

简单说就是,当匹配到 | 这个符号,就知道你用过滤器,然后就解析成 _f 去获取对应过滤器 并调用,这个过程不赘述

_f 是什么?


_f 是获取具体过滤器的函数

1_f 会在Vue 初始化的时候,注册到 Vue 的原型上

// 已简化

function installRenderHelpers(target) {

target._s = toString;

target._f = resolveFilter;

}

installRenderHelpers(Vue.prototype);

所在在 上面的 渲染函数 with 绑定当前实例vm为作用域 之后,_f 从vm 获取,成了这样 vm._f

_f 是 resolveFilter,一个可以获取 具体filter 的函数

使用 _f(“all”) 就能获取到 all 这个过滤器,resolveFilter 下面会说

怎么获取下面继续…

设置的 filter 如何被调用

由上面可以看到,_f 是 resolveFilter 赋值的,下面是 resolveFilter 源码

// 已简化

function resolveFilter(id) {

return resolveAsset(

this.$options, ‘filters’, id, true

) || identity

}

要是你看过学习vue源码(3) 手写Vue.directive、Vue.filter、Vue.component方法,相信这里你很熟悉,其实就是从this.options.filters里找对应的过滤器函数来调用,如图所示

this.options 会拿到当前组件的所有选项

你问我为什么?

根据上一个问题知道

  1. _f 会使用 实例去调用 ,vm._f 类等 vm.resolveFilter

  2. 所以,resolveFilter 的 执行上下文 this 是 vm

  3. 所以,this.$options 就是 实例的 options 啦

接着,调用 resolveAsset ,目的就是拿到 组件选项中的 具体 filter

传入 当前组件的选项 ,指定要其选项 filters ,指定具体 filter 名

function resolveAsset(

options, type, id, warnMissing

) {

// g:拿到 filters 选项

var assets = options[type];

// g:返回 调用的 filter

return assets[id]

}

_f(“all”) 流程 就成了下面这样

  1. 拿到 组件选项 中的 filters

  2. 然后再从 filters 中,拿到 all 这个filter

  3. 执行返回的 all 过滤函数时,传入需要过滤的值 parentName

  4. 得到 返回了 过滤后的值

所以,当渲染函数解析的时候,碰到使用过滤器的地方,按流程拿到过滤值后,就可以渲染到页面上了

_f(“all”)(parentName)) 就会变成 “我是过滤器” 放到 渲染函数中,最后,就是渲染到页面了

总结


fitler 其实就是从组件选项 filters 获取你设置的某个filter,并调用,然后使用你函数执行的返回值渲染

太简单了,总结跟没总结一样…

render 什么时候开始执行?

如果你看过学习vue源码(4) 手写vm.$mount方法,我相信你已经知道了

如图所示,是在挂载阶段执行的。

总结


每个模板经过 compile 都会生成一个 render 函数

render 作为 渲染三部曲的第二部,主要作用就是 执行 render,生成 Vnode

把 template 上绑定的数据,都保存到 vnode 中

然后,生成 Vnode,就是为了给 渲染三部曲的 第三部 Diff 提供源动力

从而完成 DOM 挂载

到这里其实基本就已经结束了render的思路,但是源码中有个静态render,这个 对渲染性能的提高有极大的帮助,所以必须看下。

没错,就是 静态 render,看过学习vue源码(8)手写优化器的人,应该知道什么是 静态 render

静态 render 就是用于渲染哪些不会变化的节点

大家可以先看看,Vue 是怎么判断某个节点是否是静态节点

好,下面开始我们的正文,想了想,我们还是以几个问题开始吧

1、静态 render 是什么样子的

2、静态 render 是怎么生成和 保存

3、静态 render 怎么执行

什么是 静态Render


静态 render 其实跟 render 是一样的,都是执行得到 Vnode

只是静态 render,没有绑定动态数据而已,也就是说不会变化

比如说,一个简单 render 是这样的

绑定了动态数据,需要从实例去获取

_c(‘div’,[_v(_s(aa))])

而静态 render 是这样的

没有动态数据,这个静态render 的执行结果是永远不会变的

_c(‘div’,[_c(‘span’,[_v(“1”)])])

生成保存静态Render


静态 render 是在 generate 阶段生成的,生成的方式和 render 是一样的

比如在一个模板中,有很多个静态 根节点,像这样

首先,Vue 会在遍历模板的时候,发现 span 和 strong 本身以及其子节点都是静态的

那么就会给 span 和 strong 节点本身设置一个属性 staticRoot,表示他们是静态根节点

然后这两个静态根节点就会生成自己专属的 静态 render

如果你有一直看我的Vue 笔记的话,你应该这里是会有点印象的

之后

静态 render 生成之后是需要保存的,那么保存在哪里呢?

保存在一个数组中,名叫 staticRenderFns,就是直接push 进去

当然了,此时的 push 进去的 静态 render 还是字符串,并没有变成函数

以上面的模板为例,这里的 staticRenderFns 就是这样,包含了两个字符串

staticRenderFns = [

“_c(‘span’,[_c(‘b’,[_v(“1”)])])”,

“_c(‘strong’,[_c(‘b’,[_v(“1”)])])”

]

但是在后面会逐个遍历变成可执行的函数

staticRenderFns = staticRenderFns.map(code => {

return new Function(code)

});

那么 这个 staticRenderFns 又是什么啊?

每个 Vue 实例都有一个独立的 staticRenderFns,用来保存实例本身的静态 render

staticRenderFns 的位置是

vm.$options.staticRenderFns

执行静态Render


静态 render 需要配合 render 使用,怎么说

看个例子

这个模板的 render 函数是

_c(‘div’,[

_m(0),

_v(_s(a),

_m(1)

])

_m(0) , _m(1) 就是执行的就是 静态 render 函数,然后返回 Vnode

于是 render 也可以完成 vnode 树的构建了

那么 _m 是什么呢?

在 Vue 初始化时,给Vue的原型便注册了这个函数,也就是说每个实例都继承到 _m

function installRenderHelpers(target) {

target._m = renderStatic;

}

installRenderHelpers(Vue.prototype);

再来看 renderStatic

function renderStatic(index) {

var cached = this._staticTrees || (this._staticTrees = []);

var tree = cached[index];

// 如果缓存存在,就直接返回

if (tree) return tree

// 这里是执行 render 的地方

tree = cached[index] =

this.$options.staticRenderFns[index].call(

this, null, this

);

// 只是标记静态 和 节点id 而已

markStatic(tree, “static” + index, false);

return tree

}

这个函数做的事情可以分为几件

1、执行静态render

2、缓存静态render 结果

3、标记 静态 render 执行得到的 Vnode

我们来一个个说

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

arkStatic(tree, “static” + index, false);

return tree

}

这个函数做的事情可以分为几件

1、执行静态render

2、缓存静态render 结果

3、标记 静态 render 执行得到的 Vnode

我们来一个个说

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-Znck7kTU-1712576801343)]
[外链图片转存中…(img-xsVXlI8h-1712576801344)]
[外链图片转存中…(img-qcSd9sg5-1712576801344)]
[外链图片转存中…(img-oQlTqs19-1712576801344)]
[外链图片转存中…(img-kbTQvxbc-1712576801345)]
[外链图片转存中…(img-NO4fjblQ-1712576801345)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-JHCuggTk-1712576801345)]

  • 37
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值