资讯专栏INFORMATION COLUMN

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

lansheng228 / 3043人阅读

摘要:我们都知道分为普通和作用域,两个内容都很多,所以分两部分进行讲述。今天讲的是普通其实普通,表示默认和具名,只是他们的处理方式都差不多,就只是是否有自定义名字而已,所以,表示一种类型。

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

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

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

今天我们来解读Slot 的源码啦。我们都知道 Slot 分为 普通Slot 和 作用域Slot,两个内容都很多,所以分两部分进行讲述。

今天讲的是普通Slot!

其实普通Slot,表示默认Slot和 具名Slot,只是他们的处理方式都差不多,就只是是否有自定义名字而已,所以,表示一种类型。

而我们就以默认Slot为例去探索,让我们先设置一个模板例子

父组件模板

test 组件被定义在父组件中

new Vue({    
    el: document.getElementsByTagName("div")[0],    
    components: {        
        test: {            
            template: ` 
                
我在子组件里面
` } }, data() { return { name: 11 } } })

分两个问题去看

1、插槽内容怎么解析

2、插槽如何插子页面

插槽内容怎么解析

插槽的作用域,是父实例。就是说,普通插槽的变量,都是从父实例上获取的,比如上面例子插槽内的name

根据上面的例子,父组件被解析成下面的渲染函数

with(this) {    
    return _c("div", {},
        [ _c("test", [
            "我是放在组件的 slot " + name 
          ]) 
    ], 1)
}

父渲染函数执行时,会绑定父实例为执行作用域,根据 with 的作用,test 的 slot 内的变量name,就会访问父实例上的name。

那么,当父渲染函数执行时,test组件的slot,所有变量访问父实例,并开始解析,解析的流程跟普通的模板节点是一样的

插槽怎么插入子组件

当父渲染函数执行完毕,会得到一个完整的VNode,上面存储着描述DOM 的所有信息,用于去创建需要的DOM。

上面的父组件,会得到这么一个vnode

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

可以看到

1、test组件, 被当做是 父组件的一个子元素

2、test 组件内的slot ,被当做是 test元素的子元素

虽然,并不会存在 test 这种标签的元素,但是Vue统一对待,后面才会特殊处理

1、test 组件内部解析

当父组件解析成功,得到一个vnode,那么下一步就是patch(创建DOM并插入页面)

此时,Vue会按照渲染好的vnode,生成对应的DOM 树,并插入到页面中

当Vue遍历到上面的vnode的children时,遇到了 test 这个节点,发现没有test这种标签,认定他是一个组件之后,会当做一个组件去解析

这个解析的流程不会戏说细说,不属于Slot 的内容,后面的文章会讲

2、Slot 转存

解析 test 组件时,使用 _init 方法初始化 test 组件的实例

Vue.prototype._init = function(options) {    

    var vm = this;    

    if (如果是组件) {
        initInternalComponent(vm, options);
    }
    initRender(vm);
}

初始化test实例时,上面的两个方法会起到转存 Slot 的作用

1、initInternalComponent 把 test 组件插槽节点 【 ["我是放在组件的 slot 11"] 】 传给组件选项的 【_renderChildren】 中

function initInternalComponent(vm, options) {    

// 这个options是全局选项和组件设置选项的合集
    var opts = vm.$options = 
            Object.create(vm.constructor.options);  

    var componentOptions = parentVnode.componentOptions;

    // 传给组件选项_renderChildren
    opts._renderChildren = componentOptions.children;

}

2、initRender 把上一步保存在 组件选项的【_renderChildren】 放在实例的【$slot】中

function initRender(vm) {    

    var options = vm.$options;

    // 保存给组件实例上
    vm.$slots = resolveSlots(options._renderChildren, renderContext);
}

function resolveSlots(children, context) {    

    var slots = {};    

    for (var i = 0,l = children.length; i < l; i++) {        

        var child = children[i];        
        var data = child.data;   

        if (如果是具名slot) {} 
        else { 
            (slots.default || (slots.default = [])).push(child);
        }
    }    
    return slots
}

看父组件下的 test 组件的 vnode

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

经过这两步处理,插槽节点 转存到了实例上(因为没有给名字,所以默认是default,如果给了名字,就是你给的)

testVm.$slot={ 
    default: ["我是放在组件的 slot 11"] 
}

3、slot 替换到子组件

紧接着,test 实例化初始化完毕,开始使用组件模板去构建他的渲染函数

模板被解析成下面的渲染函数

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

你可以看到,子组件的模板中的占位符 slot,被解析成了 _t 函数

_t("default")

然后,test 渲染函数执行,其中 _t("default") 先执行

_t 是 renderSlot 函数,Vue 会给每个实例都保存一个 _t

作用是根据传入的名字,返回实例上$slot 保存的对应的 【插槽节点】

function installRenderHelpers(target) {
    target._t = renderSlot;
}

function renderSlot(name) {    
    return this.$slots[name]
}

_t("default") 执行完毕,返回插槽节点,于是 test 组件渲染函数就变成下面

with(this) {    
    return _c("main", [        
        "我在子组件里面", 
        ["我是放在组件的 slot 11"]
    ], 2)
}

现在,Slot 就完全插入到子组件中啦,剩下的部分,就是渲染DOM 流程,已经跟 slot 没有关系啦

用一张图来看下流程

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

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

相关文章

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

    摘要:通过函数参数传递的形式,让插槽的变量,在解析时,先访问函数变量。那么这两个有什么关系呢外壳节点保存着所有父组件里给这个子组件绑定的数据,比如,插槽等。 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请点击 下面链接 或者 拉到 下面...

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

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

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

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

    kaka 评论0 收藏0
  • Vue原理】Compile - 源码版 之 optimize 标记静态节点

    摘要:一旦我们检测到这些子树,我们可以把它们变成常数,这样我们就不需要了在每次重新渲染时为它们创建新的节点在修补过程中完全跳过它们。否则,吊装费用将会增加好处大于好处,最好总是保持新鲜。 写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,...

    Soarkey 评论0 收藏0
  • Vue原理】VModel - 源码版之input详解

    摘要:因为失去焦点之后被强制更新了一波嗯,这就是的作用,把页面上的显示值也过滤一遍 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧 【Vue原理】VModel - 源码版之input详...

    leanxi 评论0 收藏0

发表评论

0条评论

lansheng228

|高级讲师

TA的文章

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