前言: v-slot 指令自 2.6.0 起被引入, 提供更好的支持 slot 和 slot-scope 特性的 API 替代方案. 在接下来所有的 2.x 版本中 slot 和 slot-scope 特性仍会被支持, 但已经被官方废弃且不会出现在 vue 3 中.
slot(已废弃)
1内容: 假如父组件需要在子组件内放一些 DOM, 那么这些 DOM 是显示, 不显示, 在哪个地方显示, 如何显示, 就是 slot 分发负责的活
2默认情况下, 该组件起始标签和结束标签之间的任何内容都会被抛弃
- // 父组件
- <template>
- <div id="app">
- <son > 我想显示点内容</son>
- </div>
- </template>
- // 子组件
- <template>
- <div>
- <span > 我是子组件</span>
- </div>
- </template>
3单个 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" 写出来
- // 父组件
- <template>
- <div id="app">
- <son>
- <div slot="default">我显示出来了</div>
- </son>
- </div>
- </template>
4多个 slot: 当需要多个插槽显示在不同的地方时, 需要给每个插槽加上一个 name, 并且父组件内加上 "slot=name", 使两者之间具有有关联性, 这就是具名插槽
- // 父组件
- <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>
注: 多个插槽也能有且最多只能一个默认插槽
5当没有对应插槽的 name 时
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)插槽内有默认内容, 则会直接输出插槽内的内容
- // 父组件
- <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>
6当具名插槽和默认插槽混合使用的时候, 任何没有包裹 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>
1作用域插槽或者说是一个带数据的插槽
- // 父组件
- <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>
2slot-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 版本不支持不能用了)
1默认插槽写法和以前没什么变化, v-slot 主要针对具名插槽, 作用域插槽
2具名插槽, 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> 上
3作用域插槽, 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, 但你也可以使用任意你喜欢的名字.
4作用域插槽支持 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>
5独占默认插槽的缩写语法
当子组件内只有默认插槽时, 组件的标签可以被当作插槽的模板来使用. 这样我们就可以把 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
6独占默认插槽的缩写语法不能与具名插槽混合使用
- // 父组件
- <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>
7动态插槽名, 用来来定义动态的插槽名
在 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, 语义更明朗
8v-slot 缩写为:#
具名插槽缩写为:#name
作用域插槽缩写
1)当为匿名作用域插槽时:#default = customName(#=customName 这种写法为报错)
2)当为具名作用域插槽时:#name = customName
来源: http://www.bubuko.com/infodetail-3258433.html