Vue源码学习(六):(支线)渲染函数中with(),call()的使用以及一些思考

vue,源码,学习,支线,渲染,函数,with,call,使用,以及,一些,思考 · 浏览次数 : 144

小编点评

**1.上下文** `_render`方法是在创建虚拟节点的过程中定义的,它返回一个`vnode`对象,表示虚拟节点的标签、数据、属性等信息。`vnode`对象会作为 Vue 渲染过程中真正描述节点的结构。 **2. 冻手尝试** 尝试在空白页中定义一个名为 `test()` 的函数,并使用 `_c` 方法来创建虚拟节点并打印输出,但发现该方法返回的还是 undefined。这是因为 `_c` 方法定义在 `Vue` 的原型上,而 `test()` 函数是在全局定义的。 **3. 使用 `with` 方法** 在实际代码中,我们通常使用 `with` 方法来将 `this` 指向`render` 方法的上下文,并确保 `_c,_v等方法在执行 `render` 方法的过程中具有正确的作用域。`with` 方法允许我们创建一个新的作用域,其中包含了 `this` 指向的原始上下文。 **代码分析** 这段代码展示了在 Vue 中如何使用 `with` 方法拓展作用域来创建虚拟节点并执行模板编译的过程。`_render` 方法通过 `with` 方法将作用域扩展到 `render` 方法的上下文,并使用 `this` 指向该上下文创建虚拟节点。最终,`vnode` 对象将包含了虚拟节点的标签、数据、属性等信息。

正文

好家伙,

 

昨天,在学习vue源码的过程中,看到了这个玩意

嘶,看不太懂,研究一下
 

1.上下文

这段出现vue模板编译的虚拟node部分
export function renderMixin(Vue) {
    Vue.prototype._c = function () {
        //创建标签
        return createElement(...arguments)
    }
    Vue.prototype._v = function (text) { //文本
        return createText(text)
    }
    Vue.prototype._s = function (val) {
        return val == null?"":(typeof val ==='object')?JSON.stringify(val):val
    }
    Vue.prototype._render = function () { //render函数变成 vnode
        let vm = this
        let render = vm.$options.render
        console.log(render,'||this is render')
        let vnode = render.call(this)
        // console.log(vnode)
        return vnode
    }
}
//vnode只可以描述节点

//创建元素
function createElement(tag,data={},...children){
    return vnode(tag,data,data.key,children)
}
//创建文本
function createText(text){
    return vnode(undefined,undefined,undefined,undefined,text)
}
//创建vnode
function vnode(tag,data,key,children,text){
    return {
        tag,
        data,
        key,
        children,
        text
    }
}

 

 

我实在是看不懂这个_render方法在干什么,所以我们开始研究

 

2.冻手尝试

2.1.方法返回方法

写一个简易版本,在一个空白页

 (显然这会失败,方法返回的方法未定义)

 

2.2.加上方法定义

_c = function () {
    //创建标签
    return createElement(...arguments)
}
_v = function (text) { //文本
    return createText(text)
}
_s = function (val) {
    return val == null ? "" : (typeof val === 'object') ? JSON.stringify(val) : val
}

function createElement(tag, data = {}, ...children) {
    return vnode(tag, data, data.key, children)
}
//创建文本
function createText(text) {
    return vnode(undefined, undefined, undefined, undefined, text)
}
//创建vnode
function vnode(tag, data, key, children, text) {
    return {
        tag,
        data,
        key,
        children,
        text
    }
}

function test() {
    return _c('div', _v("张三"))
}

test()

成功执行

 

2.3.回到项目

现在再回到我们的项目
我们知道,渲染函数的_c,_v,_s等方法被定义在Vue的prototype上的

不可能像上述案例这样直接定义在全局

我们在写一个例子,这里用上with()

 

同样,执行成功了

 

 所以,我们能看到,正如mdn文档所说,

在这个例子中with()方法拓展了一个test()方法的作用域链

于是,到这里,最难的问题已经解决了

 

3.代码分析

 

在这里我们知道this指向Vue实例

 

 来看这串代码

console.log(this,"||this is this")
let vnode = render.call(this)

在 JavaScript 中,.call() 方法可以用于调用函数,并且可以显式地指定函数运行时的作用域(即 this 值)。

 

于是,一切都通畅了

这一大段的代码无非做了这么几件事

1.在Vue的原型上定义_c,_v等节点处理方法

2.(  render.call(this)  )将render方法的作用域指定为this,即Vue实例本身

3.(  with(this)  )此处 with(this) 块中的 this 则指向渲染函数 render 执行时的上下文,也是 Vue 实例

4.随后,_c,_v等方法执行创建虚拟节点,返回

 

 

与Vue源码学习(六):(支线)渲染函数中with(),call()的使用以及一些思考相似的内容:

Vue源码学习(六):(支线)渲染函数中with(),call()的使用以及一些思考

好家伙, 昨天,在学习vue源码的过程中,看到了这个玩意 嘶,看不太懂,研究一下 1.上下文 这段出现vue模板编译的虚拟node部分 export function renderMixin(Vue) { Vue.prototype._c = function () { //创建标签 return

Vue源码学习(十一):计算属性computed初步学习

好家伙, 1.Computed实现原理 if (opts.computed) { initComputed(vm,opts.computed); } function initComputed(vm, computed) { // 存放计算属性的watcher const watchers = vm

Vue源码学习(一):数据劫持(对象类型)

好家伙,了解一下Vue如何实现数据劫持 1.Vue中data的使用 首先,我得搞清楚这玩意的概念,我们先从vue的使用开始吧 想想看,我们平时是如何使用vue的data部分的? 无非是这两种情况 (你可千万不要带着惊讶的表情说"啊!原来有两种写法的吗") //函数写法 data() { return

Vue源码学习(二):渲染第一步,模板解析

好家伙, 1.去哪了 在正式内容之前,我们来思考一个问题, 当我们使用vue开发页面时,中的内容是如何变成我们网页中的内容的? 它会经历四步: 解析模板:Vue会解析中的内容,识别出其中的指令、插值表达式({{}}),以及其他元素和属性。

Vue源码学习(三):渲染第二步,创建ast语法树

好家伙,书接上回 在上一篇Vue源码学习(二):渲染第一步,模板解析中,我们完成了模板解析 现在我们继续,将模板解析的转换为ast语法树 1.前情提要 代码已开源https://github.com/Fattiger4399/analytic-vue.git手动调试一遍, 胜过我

Vue源码学习(四):渲染第三步,将ast语法树转换为渲染函数

好家伙, Vue源码学习(三):渲染第二步,创建ast语法树, 在上一篇,我们已经成功将 我们的模板 转换为ast语法树 接下来我们继续进行操作 1.方法封装 由于代码太多,为了增加代码的可阅读性 我们先将代码进行封装 index.js import { generate } f

Vue源码学习(五):渲染第四步,生成虚拟dom并将其转换为真实dom

好家伙, 前情提要: 在上一篇我们已经成功将ast语法树转换为渲染函数 现在我们继续 1.项目目录 代码已开源https://github.com/Fattiger4399/analytic-vue.git手动调试一遍, 胜过我解释给你听一万遍 新增文件:vnode/index.js vnode/p

Vue源码学习(七):合并生命周期(混入Vue.Mixin)

好家伙, 1.使用场景 现在来,来想一下,作为一个使用Vue的开发者,假设现在我们要使用created(),我们会如何使用 1.1. .vue文件中使用 {{ message }}

Vue源码学习(十):关于dep和watcher使用的一些思考

好家伙, 前面想了好久,都没想明白为什么要dep和watcher打配合才能实现数据-视图同步 为什么要多一个依赖管理这样的东西 给每个数据绑个watcher(xxfunction),然后,数据变了,调set,然后调xxfunction,不就行了, 然后今天突然想明白了,不是为什么要这么干,而是必须这

Vue源码学习(九):响应式前置:实现对象的依赖收集(dep和watcher)

好家伙,这是目前为止最绕的一章,也是十分抽象的一章 由于实在太过抽象,我只能用一个不那么抽象的实例去说服我自己 完整代码已开源https://github.com/Fattiger4399/analytic-vue.git 1.我们要做什么? 来看这个例子, index.html setTimeou