细说Vue作用域插槽,匹配应用场景。

时间:2022-03-11 18:49:09

最近在官方文档中看到,vue新增了一种插槽机制,叫做作用域插槽。要求的版本是2.1.0+。

首先来说一下:顾名思义,所谓作用域插槽,主要就在作用域,需要注意的是(以下几点看不懂不要紧,配合下面的例子,你会一看就懂):

1. 组件中的slot标签只能有有一个,而这一个slot用于替代组件调用时的多个标签。即一个slot代替一组范围的标签,即为作用域。

2. 作用域插槽的特殊在于:可在上层作用域中通过临时变量拿到组件定义时通过作用域插槽传递的数据。

3. 作用域插槽的技巧在于:可在上层作用域中通过拿到的数据选择性地渲染标签(即修改slot对应的标签范围)。

下面通过实际例子来一步一步地细说:

**拥有作用域插槽的组件定义(实际代码中组件要在根实例创建之前定义):

        Vue.component("list-tpl", {
props: ["list"],
template: `
<ul>
<li style="display:block;" v-for="(item, index) in list">
<slot :item="item"></slot> // item为向上层传递的数据,单个slot在调用时转化为作用域内的多个标签
</li>
</ul>
`
})

*根实例代码,主要包括测试数据:

var app = new Vue({
el: "#app",
data: {
list: [
{
name: "tate",
age: 26,
single: true, // 是否单身
stu: false // 是否是学生
},
{
name: "kevin",
age: 23,
single: true,
stu: true
},
{
name: "harden",
age: 28,
single: false,
stu: false
},
{
name: "Jimmy",
age: 29,
single: false,
stu: true
}
]
}
})

*最重要的 组件调用

        <list-tpl :list="list">
<!-- 调用的时候 a 为临时变量,只用于获取数据 -->
<template slot-scope="a">
<!-- 若不加任何判断,整个template中的标签都会替换为定义时的slot -->
<h4>{{a.item.name}}</h4>
<h5>{{a.item.age}}</h5>
<!-- 技巧就在于通过a拿到的数据选择性地渲染标签,即修改单个slot对应的作用域范围 -->
<span v-if="a.item.single">我是单身</span>
<span v-if="a.item.stu">我是学生</span>
<span v-if="!a.item.single">我不是单身</span>
<span v-if="!a.item.stu">我不是学生</span>
</template>
</list-tpl>

综上:作用于插槽主要应用在:需要在实际调用组件时选择性渲染插槽内容,而不是在定义时用js写。

*下面看一下本例子的实际效果:

细说Vue作用域插槽,匹配应用场景。

*本例的全部代码如下,可自行运行查看效果:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<slot-test>
<template slot="top">定制top</template>
</slot-test>
<list-tpl :list="list">
<!-- 调用的时候 a 为临时变量,只用于获取变量 -->
<template slot-scope="a">
<!-- 若不加任何判断,整个template中的标签都会替换为定义时的slot -->
<h4>{{a.item.name}}</h4>
<h5>{{a.item.age}}</h5>
<!-- 技巧就在于通过a拿到的数据选择性地渲染标签,即修改单个slot对应的作用域范围 -->
<span v-if="a.item.single">我是单身</span>
<span v-if="a.item.stu">我是学生</span>
<span v-if="!a.item.single">我不是单身</span>
<span v-if="!a.item.stu">我不是学生</span>
</template>
</list-tpl>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
<script>
Vue.component("slot-test", {
template: "<div>\
<slot name='top'>\
<p>默认top</p>\
</slot>\
<slot name='mid'>\
<p>默认mid</p>\
</slot>\
<slot name='bottom'>\
<p>默认bototm</p>\
</slot>\
</div>" })
Vue.component("list-tpl", {
props: ["list"],
template: `
<ul>
<li style="display:block;" v-for="(item, index) in list">
<slot :item="item"></slot> // item为向上层传递的数据,单个slot在调用时转化为作用域内的多个标签
</li>
</ul>
`
})
var app = new Vue({
el: "#app",
data: {
list: [
{
name: "tate",
age: 26,
single: true,
stu: false
},
{
name: "kevin",
age: 23,
single: true,
stu: true
},
{
name: "harden",
age: 28,
single: false,
stu: false
},
{
name: "Jimmy",
age: 29,
single: false,
stu: true
}
]
}
})
</script>
</body>
</html>