Vue插槽:slot、slot-scope、v-slot

前言:v-slot 指令自 2.6.0 起被引入,提供更好的支持 slot 和 slot-scope 特性的 API 替代方案。在接下来全部的 2.x 版本中 slot 和 slot-scope 特性仍会被支持,但已经被官方废弃且不会出如今 Vue 3 中。数据结构

slot(已废弃)

①内容:假如父组件须要在子组件内放一些DOM,那么这些DOM是显示、不显示、在哪一个地方显示、如何显示,就是slot分发负责的活app

②默认状况下,该组件起始标签和结束标签之间的任何内容都会被抛弃函数

//父组件
<template>
    <div id="app">
        <son>我想显示点内容</son>
    </div>
</template>

//子组件
<template>
    <div>
        <span>我是子组件</span>
    </div>
</template>

③单个slot:当父组件须要显示一些东西在子组件里时,只须要将这个<slot>放置于子组件想要显示的地方便可,若没有name,则为默认插槽(匿名插槽),一个不带name<slot>出口会带有隐含的名字“default”。优化

//父组件
<template>
    <div id="app">
        <son>
       <div>我显示出来了</div>
     </son> </div> </template> //子组件 <template> <div> <p><slot></slot></p> <p>我是子组件</p> </div> </template>

上述代码中父组件等同于下面的代码,二者之间的区别是是否将隐含的“default”写出来this

//父组件
<template>
    <div id="app">
        <son>
            <div slot="default">我显示出来了</div>
        </son>
    </div>
</template>

④多个slot:当须要多个插槽显示在不一样的地方时,须要给每一个插槽加上一个name,而且父组件内加上"slot=name",使二者之间具备有关联性,这就是具名插槽spa

//父组件
<template>
    <div id="app">
        <son>
            <div slot="slotOne">我是插槽一</div>
            <div slot="slotTwo">我是插槽二</div>
            <div slot="slotThree">我是插槽三</div>
        </son>
    </div>
</template>

//子组件
<template>
    <div>
        <p><slot name="slotOne"></slot></p>
        <p><slot name="slotTwo"></slot></p>
        <p class="content">我是子组件</p>
        <p><slot name="slotThree"></slot></p>
    </div>
</template>

注:多个插槽也能有且最多只能一个默认插槽code

⑤当没有对应插槽的name时component

1)插槽里没有默认的内容,则会什么的都不输出对象

//父组件
<template>
    <div id="app">
        <son>
            <div>我想插入进去</div>
        </son>
    </div>
</template>

//子组件
<template>
    <div>
        <p class="content">我是子组件</p>
        <p><slot name="slotOne"></slot></p>
    </div>
</template>

 2)插槽内有默认内容,则会直接输出插槽内的内容blog

//父组件
<template>
    <div id="app">
        <son>
            <div>我想插入进去</div>
        </son>
    </div>
</template>

//子组件
<template>
    <div>
        <p class="content">我是子组件</p>
        <p><slot name="slotOne">没有对应name时,我会显示</slot></p>
    </div>
</template>

⑥当具名插槽和默认插槽混合使用的时候,任何没有包裹slot(或者slot="default")的都将视为默认插槽的内容,对于包裹相同slot值的标签会渲染在同一个位置

//父组件
<template>
    <div id="app">
        <son>
        <div>匿名插槽第一段内容</div>
        <div slot="slotOne">相同具名一</div>
        <div>匿名插槽第二段内容</div>
        <div slot="slotOne">相同具名二</div>
        匿名插槽第三段内容
        </son>
    </div>
</template>

//子组件
<template>
    <div>
        <p style="border:1px solid #0ff"><slot></slot></p>
        <p style="border:1px solid #f00"><slot name="slotOne"></slot></p>
    </div>
</template>

slot-scope(已废弃)

本文全部做用域插槽,子组件里news的数据

<script>
export default {
    name: "name",
    data(){
        return{
            news:[
                '十九届四中全会28日至31日在京召开',
                '珍爱和平团结合做 构建人类命运共同体',
                '法治是最好的营商环境',
                '夯实优化营商环境的法治基石',
                '中国营商环境全球排名再前进15名!'
            ],
        }
    }
}
</script>

①做用域插槽或者说是一个带数据的插槽

//父组件
<template>
    <div id="app">
        <son>
            <template slot="news" slot-scope="newsData">
                <ul>
                    <li v-for="(item,index) in newsData.newsList" :key="index">{{item}}</li>
                </ul>
            </template>
        </son>
    </div>
</template>

//子组件
<template>
    <div>
        <p class="content">我是子组件</p>
        <p><slot name="news" :newsList = 'news'></slot></p>
    </div>
</template>

 

这里有小坑:

1)这里的 slot-scope 声明了被接收的 prop 对象会做为 newData 变量存在于 <template> 做用域中。你能够像命名 JavaScript 函数参数同样随意命名 newData 。

2)这时的newData数据结构为: 

newsData:{
    newsList:[
        '十九届四中全会28日至31日在京召开',
        '珍爱和平团结合做 构建人类命运共同体',
        '法治是最好的营商环境',
        '夯实优化营商环境的法治基石',
        '中国营商环境全球排名再前进15名!'
    ]
}

3)slot-scope 特性也能够直接用于非 <template> 元素 

<template>
    <div id="app">
        <son>
            <div slot="news" slot-scope="newsData">
                <ul>
                    <li v-for="(item,index) in newsData.newsList" :key="index">{{item}}</li>
                </ul>
            </div>
        </son>
    </div>
</template>

②slot-scope接收到的值也可使用ES6解构

<template>
  <div id="app">
    <son>
      <div slot="news" slot-scope="{news}">
        <ul>
          <li v-for="(item,index) in news" :key="index">{{item}}</li>
        </ul>
      </div>
    </son>
  </div>
</template>

v-slot

重点来了,v-slot是 v2.6.0 引入的新的指令,目的是为了更好的支持slot、slot-scope的特性(其实就是把两个统一块儿来),新人上位,老人就应该退居幕后,并辅佐一段时间,因此slot、slot-scope在v2.6.0正式废弃(后续的2.x版本依旧支持,但不推荐),在未来的v3.x版本中正式废除(就是3.x版本不支持不能用了)

①默认插槽写法和之前没什么变化,v-slot主要针对具名插槽、做用域插槽

②具名插槽,v-slot:name

//父组件
<template>
    <div id="app">
        <son>
            <template v-slot:slotOne>我想显示一点内容</template>
        </son>
    </div>
</template>

//子组件
<template>
    <div>
        <p><slot name="slotOne"></slot></p>
    </div>
</template>

这里有小坑

1)除独占默认插槽的缩写语法外,v-slot 只能添加在一个 <template> 上

③做用域插槽,v-slot:name = customName

绑定在 <slot> 元素上的特性被称为插槽 prop。如今在父级做用域中,咱们能够给 v-slot 带一个值来定义咱们提供的插槽 prop 的名字

//父组件
<template>
    <div id="app">
        <son>
            <template v-slot:news = "newsData">
                <ul>
                    <li v-for="(item,index) in newsData.newsList" :key="index">
                        {{index}}、{{item}}
                    </li>
                </ul>
            </template>
        </son>
    </div>
</template>

//子组件
<template>
    <div>
        <p><slot name="news" :newsList = 'news'></slot></p>
    </div>
</template>

在这个例子中,咱们选择将包含全部插槽 prop 的对象命名为 newsData,但你也可使用任意你喜欢的名字。

④做用域插槽支持ES6解构

将上述例子中父组件改一下

<template>
    <div id="app">
        <son>
            <template v-slot:news = "{newsList}">
                <ul>
                    <li v-for="(item,index) in newsList" :key="index">
                        {{index}}、{{item}}
                    </li>
                </ul>
            </template>
        </son>
    </div>
</template>

⑤独占默认插槽的缩写语法

当子组件内只有默认插槽时,组件的标签能够被看成插槽的模板来使用。这样咱们就能够把 v-slot 直接用在组件上

//父组件
<template>
    <div id="app">
        <son v-slot="{news}">
            <ul>
                <li v-for="(item,index) in news" :key="index">
                    {{item}}
                </li>
            </ul>
        </son>
    </div>
</template>

//子组件
<template>
    <div>
        <p><slot :news="news"></slot></p>
    </div>
</template>

这里有小坑

1)当子组件内只有默认插槽时,能够省略default,写做:v-slot = customName

2)当子组件内只有默认插槽时,若是v-slot也准备使用缩写时(#),default不能被省略,写做:#default = customName

⑥独占默认插槽的缩写语法不能与具名插槽混合使用

//父组件
<template>
    <div id="app">
        <son v-slot="{news}">
            <ul>
                <li v-for="(item,index) in news" :key="index">
                    {{item}}
                </li>
            </ul>
            <div v-slot:mixinSlot>默认插槽的缩写语法和具名插槽混用,致使做用域不明确</div>
        </son>
    </div>
</template>

//子组件
<template>
    <div>
        <p><slot :news="news"></slot></p>
        <p><slot name="mixinSlot"></slot></p>
    </div>
</template>

⑦动态插槽名,用来来定义动态的插槽名

在v2.6.0版本中新增动态参数,能够用方括号([])括起来的 JavaScript 表达式做为一个指令的参数,动态参数我将在另外一篇文章叙述

//父组件
<template>
    <div id="app">
        <son>
            <template v-slot:[slotName] ='{ news }'>
                <ul>
                    <li v-for="(item,index) in news" :key="index">{{item}}</li>
                </ul>
            </template>
        </son>
    </div>
</template>

<script>
import son from "./components/son";

export default {
    name: "App",
    components: {
        son
    },
    data(){
        return{
            isOK: false
        }
    },
    computed: {
        slotName(){
            return this.isOK ? 'slot1' : 'slot2'
        }
    },
};
</script>

//子组件
<template>
    <div>
        <slot name="slot1" :news='news'></slot>
        <slot name="slot2" :news='news2'></slot>
    </div>
</template>

<script>
export default {
    name: "name",
    data() {
        return {
            news: [
                "十九届四中全会28日至31日在京召开",
                "珍爱和平团结合做 构建人类命运共同体",
                "法治是最好的营商环境",
                "夯实优化营商环境的法治基石",
                "中国营商环境全球排名再前进15名!"
            ],
            news2: [
                '27省份前三季度GDP出炉 16省份GDP增速跑赢全国',
                '新航季来了!这些航班将飞大兴机场,坐飞机别走错',
                '北方回暖南方雨连绵 江南等多地气温将创新低',
                '水润民心 脱贫路上“领头雁”  钟声',
                '看看第六届世界互联网大会国际组织说了啥'
            ]
        };
    }
};
</script>

印象中,好像没什么地方须要用到动态插槽名,若是有大大遇到须要使用,还请留言,很是感谢,上述栗子若是用v-if,语义更明朗

⑧v-slot缩写为:#

具名插槽缩写为:#name

做用域插槽缩写

1)当为匿名做用域插槽时:#default = customName(#=customName这种写法为报错)

2)当为具名做用域插槽时:#name = customName