vue中的slot(插槽)

什么是插槽
  • 插槽(Slot)是Vue提出来的一个概念,正如名字一样,插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。
  • 插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制
默认插槽-1
<!--子组件-->
<template>
    <div>
        <slot></slot>
        <div>slot固有内容</div>
    </div>
</template>
<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot></named-slot>
    </div>
</template>

当父组件不在插槽中写入任何数据时,会只显示父组件和子组件的默认内容:


默认插槽-1
默认插槽-2
<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot>
            我是父组件中的匿名插槽内容
            <div style="color: red">我是父组件中的匿名插槽内容</div>
            <el-button>插槽按钮</el-button>
        </named-slot>
    </div>
</template>

当需要在子组件slot位置显示内容时,可以在父组件引入的子组件中写入想要现实的内容(可以直接写入内容,或者使用标签,或者使用其他组件)


默认插槽-2
默认插槽-3

也可以为插槽设置具体的默认内容,它只会在没有提供内容的时候被渲染

<!--子组件-->
<template>
    <div>
        <slot>子组件插槽默认内容</slot>
        <div>slot固有内容</div>
    </div>
</template>
<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot></named-slot>
    </div>
</template>

父组件没有提供内容时,显示子组件的插槽默认内容:


默认插槽-3
默认插槽-4
<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot>
            我是父组件中的插槽内容,我会替换子组件slot中的默认内容
        </named-slot>
    </div>
</template>

父组件提供内容时,子组件的默认内容被父组件提供的内容替换:


默认插槽-4
具名插槽-1

有时候我们需要多个插槽,以把不同的内容显示在需要的地方
一个不带 name<slot> 出口会带有隐含的名字“default”。

<!--子组件-->
<template>
    <div>
        <slot name="header"></slot>
        <div>slot固有内容</div>
        <slot></slot>
        <div>slot固有内容</div>
        <slot name="footer"></slot>
    </div>
</template>
<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot>
            <div>默认插槽1</div>
            <div slot="footer">底部插槽</div>
            <div slot="header">顶部插槽</div>
            <div>默认插槽2</div>
            <div slot="default">默认插槽3</div>
        </named-slot>
    </div>
</template>

上面的代码显示内容如下:


具名插槽-1
具名插槽-2

在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称
注意 v-slot 只能添加在 <template> 上 (只有一种例外情况)
所以父组件的写法也可以是这样:

<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot>
            <template>默认插槽1</template>
            <template v-slot:footer>底部插槽</template>
            <template v-slot:header>顶部插槽</template>
            <template>默认插槽2</template>
        </named-slot>
    </div>
</template>

显示如下:


具名插槽-2.1

或者写成这样:

<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot>
            <template v-slot:footer>底部插槽</template>
            <template v-slot:header>顶部插槽</template>
            <template v-slot:default>默认插槽3</template>
        </named-slot>
    </div>
</template>

显示如下:

具名插槽-2.2

当使用v-slot时,只会显示最后一个带有v-slot<template>元素中的内容

<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot>
            <template v-slot:default>默认插槽1</template>
            <template v-slot:footer>底部插槽</template>
            <template v-slot:header>顶部插槽</template>
            <template v-slot:default>默认插槽2</template>
            <template>默认插槽3</template>
        </named-slot>
    </div>
</template>

以上代码显示:


具名插槽-2.3
具名插槽的缩写

v-onv-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header:

<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot>
            <template #default>默认插槽1</template>
            <template #footer>底部插槽</template>
            <template #header>顶部插槽</template>
        </named-slot>
    </div>
</template>

上面代码显示为:

具名插槽的缩写

然而,和其它指令一样,该缩写只在其有参数的时候才可用。这意味着以下语法是无效的:
(官网写会触发警告,我的页面直接报错了......)

<!-- 这样会触发一个警告 -->
<named-slot>
    <template #>顶部插槽</template>
</named-slot>

所以如果想使用缩写的话,还是老老实实地写清楚插槽名称吧

编译作用域

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
当你想在一个插槽中使用数据时,例如下例,想在父组件中使用子组件的数据是访问不到的:

<!--子组件-->
<template>
    <div>
        <slot></slot>
        <div>slot固有内容: {{ child }}</div>
    </div>
</template>

<script>
    export default {
        name: "mySlot",
        data() {
            return {
                child: "子组件属性"
            }
        }
    }
</script>
<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot>
            <div>我是父组件中的匿名插槽内容: {{ child }}</div>
        </named-slot>
    </div>
</template>
作用域插槽

有时让插槽内容能够访问子组件中才有的数据是很有用的。

<!--子组件-->
<template>
    <div>
        <slot :data="user"></slot>
        <div>slot固有内容: {{ user.name }}</div>
    </div>
</template>

<script>
    export default {
        name: "mySlot",
        data() {
            return {
                user: {
                    name: "明妃",
                    age: "18"
                }
            }
        }
    }
</script>
<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot>
            <template slot-scope="slotProps">我是父组件中的匿名插槽内容: {{ slotProps.data.name }}</template>
        </named-slot>
    </div>
</template>

其中子组件中:data="user"用来把子组件中的user绑定到data
父组件中slotProps用来接收子组件传过来的数据,slotProps.data即是子组件传递过来的user
上面代码显示如下:

作用域插槽

自2.6.0之后,slot-scope已弃用,所以也可以下面的写法:

<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot>
            <template v-slot:default="slotProps">我是父组件中的匿名插槽内容: {{ slotProps.data.name }}</template>
        </named-slot>
    </div>
</template>
独占默认插槽的缩写语法

在上述情况下,当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot 直接用在组件上:

<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot v-slot:default="slotProps">
            我是父组件中的匿名插槽内容: {{ slotProps.data.name }}
        </named-slot>
    </div>
</template>

这种写法还可以更简单。就像假定未指明的内容对应默认插槽一样,不带参数的 v-slot 被假定对应默认插槽:

<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot v-slot="slotProps">
            我是父组件中的匿名插槽内容: {{ slotProps.data.name }}
        </named-slot>
    </div>
</template>

这两种写法都可以获得跟上面一样的效果:

独占默认插槽的缩写语法

注意默认插槽的缩写语法不能与具名插槽混用,因为他会导致作用域不明确
只要出现多个插槽,请始终为所有的插槽使用完整的基于<template>的语法

动态插槽名

动态指令参数也可以用在v-slot 上,来定义动态的插槽名:

<!--子组件-->
<template>
    <div>
        <slot name="header"></slot>
        <div>slot固有内容</div>
        <slot></slot>
        <div>slot固有内容</div>
        <slot name="footer"></slot>
    </div>
</template>
<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot>
            <template v-slot:[slotNameC]>看看插槽位置</template>
        </named-slot>
    </div>
</template>

data() {
    return{
        slotNameC: "footer",    // footer,header,default
    }
},

slotNameC赋不同的值,插槽内容会显示在对应位置
但是下面的写法会报错:

<!--父组件-->
<template>
    <div class="content">
        <div>我是父组件</div>
        <named-slot>
            <template v-slot:[slotNameA]>默认插槽</template>
            <template v-slot:[slotNameB]>顶部插槽</template>
            <template v-slot:[slotNameC]>底部插槽</template>
        </named-slot>
    </div>
</template>

data() {
    return{
        slotNameA: "default",
        slotNameB: "header",
        slotNameC: "footer",    // footer,header,default
    }
},

只有注释掉上面两行才可以正常显示,注释掉第三行不能正常显示(只剩第一行或第二行都不行),目前还不知道原因,希望知道原因的小伙伴告诉一下

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容