• Vue渲染函数中with(),call()的使用
  • 发布于 2个月前
  • 185 热度
    0 评论
昨天,在学习vue源码的过程中,看到了这个玩意

嘶,看不太懂,研究一下
一.上下文
这段出现vue模板编译的虚拟node部分
export function renderMixin(Vue) {
    Vue.prototype._c = function () {
        // 堆代码 duidaima.com
        //创建标签
        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.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()方法的作用域链。于是,到这里,最难的问题已经解决了。
三.代码分析

在这里我们知道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等方法执行创建虚拟节点,返回
用户评论