资讯专栏INFORMATION COLUMN

【Vue原理】Slot - 源码版之作用域插槽

tolerious / 623人阅读

摘要:通过函数参数传递的形式,让插槽的变量,在解析时,先访问函数变量。那么这两个有什么关系呢外壳节点保存着所有父组件里给这个子组件绑定的数据,比如,插槽等。

写文章不容易,点个赞呗兄弟
专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧
研究基于 Vue版本 【2.5.17】

如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧

【Vue原理】Slot - 源码版之作用域插槽

今天探索Slot的另一部分,作用域插槽。

首先,设置一个模板例子

把子组件的 child 传给 插槽

父组件会解析成下面的渲染函数

with(this) {    

    return _c("div", {},

        [_c("test", { 

            scopedSlots: _u([{                

                key: "default",                

                fn: function(slotProps) {                   

                    return [ "我是放在组件的 slot :"+slotProps ]

                }
            }])

        })],    

    1)

}

其中,_u 是 resolveScopedSlots,Vue会给每个实例都注册一个 _u 方法。

作用主要是把数组变成对象map并返回

看下 resolveScopedSlots 源码

给每个实例注册 _u

function resolveScopedSlots(fns, res) {
    res = res || {};    
    for (var i = 0; i < fns.length; i++) { 

        res[fns[i].key] = fns[i].fn;
    }    
    return res
}

把传入的数组组装成对象,像是下面这样

[{    
    key: "default",    
    fn: function(slotProps) {        
        return ["我是放在组件的 slot :" + slotProps]

    }
}]

---------_u 把上面变成下面------

{    
    default:function(slotProps) {        
        return ["我是放在组件的 slot :" + slotProps]
    }
}
插槽怎么解析

你可以看到了,在父组件的渲染函数中,作用域Slot 被包装成了一个函数,并且保存在 test 组件的 scopeSlot 中,用于后面解析内部组件时使用

包装成函数,是为了改变插槽内容的变量访问的作用域。

通过函数参数传递的形式,让插槽的变量,在解析时,先访问函数变量。如果没有,再去父组件上获取

那么这个函数的参数是从哪里传进来的呢?让我们一探究竟

额外:组件解析

上面的 test 在父组件中解析成一个节点

{    
    tag:"test",    
    children:["我是放在组件的 slot :11"]
}

而解析 test 时,也会被解析成一个节点

{    
    tag:"main",    
    children:["我在子组件里面","我是放在组件的 slot :11"]
}

就是 test 会有两个节点,第一个节点我认为是外壳节点,第二个节点是渲染节点,是真正插入页面的。

那么这两个有什么关系呢?外壳节点保存着所有父组件里给这个子组件绑定的数据,比如 props,插槽等。然后提供给 组件解析时使用

按顺序理一下解析流程

1、插槽函数保存到外壳节点

之前的父渲染函数,子组件的插槽解析成一个节点处理函数,如下 ,然后作为 scopedSlots 保存在 test 组件的外壳节点上

{    
    tag:"test",    
    data:{
        scopedSlots:{
            // 插槽包装成的函数
            default:function(slotProps) {                   
                return [ "我是放在组件的 slot :"+slotProps ]
            }
        }
    },
    children:["我是放在组件的 slot :11"]
}

2、插槽函数另存为

然后,test组件会创建自身实例,并且初始化,在初始化的过程中,会把 外壳节点上的 $scopedSlots 另存为到本实例上,方便后面子组件解析内部模板直接调用

// 这个函数作用是,执行渲染函数,得到组件节点
Vue.prototype._render = function() {    

    var vm = this;    
    var ref = vm.$options; 

    // _parentVnode 就是外壳节点
    var _parentVnode = ref._parentVnode; 

    if (_parentVnode) {
        vm.$scopedSlots = _parentVnode.data.scopedSlots || {};
    }
    ...省略N多执行渲染函数的代码
    vm.$vnode = _parentVnode;    
    return vnode
};

3、子组件解析内部

看下子组件模板,绑定了child在 slot 上,用于传给插槽

执行子组件解析成的渲染函数如下

with(this) {    
    return _c("main", [        
        "我在子组件里面",
        _t("default", null, {            
            child: child
        })
    ], 2)
}

其中,child 会从子组件上获取,所以 child 是11

渲染函数中,看到子组件中的slot的占位标签如下

被解析成了一个_t函数(怎么解析的话,又是一篇,太多先不说)

_t("default", null, { child:child })

看下_t,他是renderSlot,上一篇文章提过。这个方法,会兼容处理作用域Slot和普通Slot,上篇文章省略了处理作用域Slot 的代码,现在看一下

function renderSlot(name, fallback, props) {   

    // 看了上面,所以可以从实例上获取$scopedSlots
    var scopedSlotFn = this.$scopedSlots[name];   
    var nodes;    

    if (scopedSlotFn) {
        props = props || {};

        // 开始执行插槽函数
        nodes = scopedSlotFn(props);
    }    
    return nodes
}

_t 的作用是,执行会直接返回节点,直接替换子组件 slot 占位符,完成插入功能

_t 就是 renderSlot ,函数会根据 【插槽名字】 找到对应的 【作用域Slot包装成的函数】,然后执行它,把子组件内的数据 【 { child:child } 】子传进去

于是,作用域Slot 生成的函数,就接收到了子组件传入的数据啦

所以 作用域Slot 就可以拿传入的参数进行解析了

插槽怎么插入子组件

_t("default",null,{ child:child }) 执行完毕,会返回节点,这个节点就是 slot 解析生成的节点

[ "我是放在组件的 slot :"+ {child:11} ]

子组件渲染函数执行完毕,生成的vnode 如下

{    
    tag:"main",    
    children:[
        "我在子组件里面",
        "我是放在组件的 slot : {child:11}"
    ]
}

作用域插槽,成功地替换了原来的占位符 ,当上了正宫娘娘

最后,来张图看下总的流程

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105321.html

相关文章

  • Vue原理Slot - 源码版之普通插槽

    摘要:我们都知道分为普通和作用域,两个内容都很多,所以分两部分进行讲述。今天讲的是普通其实普通,表示默认和具名,只是他们的处理方式都差不多,就只是是否有自定义名字而已,所以,表示一种类型。 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请...

    lansheng228 评论0 收藏0
  • Vue原理Slot - 白话版

    摘要:写文章不容易,点个赞呗兄弟专注源码分享,文章分为白话版和源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于版本如果你觉得排版难看,请点击下面链接或者拉到下面关注公众号也可以吧原理白话版插槽作为组件一个重要的部 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于...

    chanthuang 评论0 收藏0
  • Vueslot-scope的场景的个人理解

    摘要:网络上大多数文章,也是千篇一律的翻译这句话,可是仅凭这一句话,我想象不到的使用场景。因为真正的使用场景下,子组件的数据都是来自父组件的。组件的数据都是来自调用者的,然后会把每一行的,在开发者需要时,传递出去。 Vue的slot-scope的场景的个人理解 这篇文章不是单纯把文档的话和api拿来翻译和演示,而是谈谈我对于slot-scope的使用场景的个人理解,如果理解错误,欢迎讨论! ...

    Forest10 评论0 收藏0
  • 细谈 vue - slot

    摘要:结合我们的例子,子组件则会生成以下代码到目前为止,对于普通插槽和作用域插槽已经谈的差不多了。下面我们将仔细谈谈这块的内容。在看具体实现逻辑前,我们先通过一个例子来先了解下其基本用法然后进行使用页面展示效果如下看着好。本篇文章是细谈 vue 系列第二篇了,上篇我们已经细谈了 vue 的核心之一 vdom,传送门 今天我们将分析我们经常使用的 vue 功能 slot 是如何设计和实现的,本文将围...

    kaka 评论0 收藏0
  • vue 2.6.0 具名插槽作用插槽

    摘要:后将已废弃的使用特性的语法废除,但是目前还能够使用,链接地址如图实现一个类似,星级点评的组件父组件子组件子组件将绑定再传给父组件的再通过获得传过来的值,官方解释作用域插槽的内部工作原理是将你的插槽内容包括在一个传入单个参数的函数里插槽 vue 2.6.0后将已废弃的使用 slot-scope 特性的语法废除,但是目前还能够使用,链接地址:https://cn.vuejs.org/v2/...

    MorePainMoreGain 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<