老版本vue

模板中只能有一个根元素

HTML内容模板(

1
2
3
4
5
6
7
8
9
<div id="app">
<modal></modal>
</div>

<template id="modal">
<div>
<h1>是否删除</h1>
</div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
let modal = {
template:"#modal"
}

const app = new Vue({
el:'#app',
components:{
modal
},
data:{
}
})

我们通常是想把h1的值动态放入,所以就要用到插槽

单个插槽 | 默认插槽 | 匿名插槽

首先是单个插槽,单个插槽是vue的官方叫法,但是其实也可以叫它默认插槽,或者与具名插槽相对,我们可以叫它匿名插槽。因为它不用设置name属性。
单个插槽可以放置在组件的任意位置,但是就像它的名字一样,一个组件中只能有一个该类插槽。相对应的,具名插槽就可以有很多个,只要名字(name属性)不同就可以了。

1
2
3
4
5
6
7
8
9
10
11
<div id="app">
<modal>
<h1>插入成功</h1>
</modal>
</div>

<template id="modal">
<div>
<slot></slot>
</div>
</template>

image.png

当我们看到插入成功的时候,匿名插入就实现了

具名插槽

匿名插槽没有name属性,所以是匿名插槽,那么,插槽加了name属性,就变成了具名插槽。具名插槽可以在一个组件中出现N次,出现在不同的位置。下面的例子,就是一个有两个具名插槽单个插槽的组件,这三个插槽被父组件用同一套css样式显示了出来,不同的是内容上略有区别。

简单的来说,就是,我们可能遇到一个问题
我们想插入不同的插槽内的内容不一样

在 2.6.0+ 中已弃用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="app">
<modal>
<h1>插入成功</h1>
<h2 slot="title">标题</h2>
<h2 slot="content">内容</h2>
</modal>
</div>

<template id="modal">
<div>
<slot name="default"></slot>
<slot name="title"></slot>
<slot name="content"></slot>
</div>
</template>

我们可以发现没有name的情况下,默认就是default

作用域插槽 | 带数据的插槽

最后,就是我们的作用域插槽。这个稍微难理解一点。官方叫它作用域插槽,实际上,对比前面两种插槽,我们可以叫它带数据的插槽。什么意思呢,就是前面两种,都是在组件的template里面写

在 2.6.0+ 中已弃用


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>Vue作用域插槽</title>
<script src="https://cdn.bootcss.com/vue/2.3.4/vue.js"></script>
</head>

<body>
<div id="app2">
<!-- 组件使用者只需传递users数据即可 -->
<my-stripe-list :items="users" odd-bgcolor="#D3DCE6" even-bgcolor="#E5E9F2">
<!-- props对象接收来自子组件slot的$index参数 -->
<template slot="cont" scope="props">
<span>{{users[props.$index].id}}</span>
<span>{{users[props.$index].name}}</span>
<span>{{users[props.$index].age}}</span>
<!-- 这里可以自定[编辑][删除]按钮的链接和样式 -->
<a :href="'#edit/id/'+users[props.$index].id">编辑</a>
<a :href="'#del/id/'+users[props.$index].id">删除</a>
</template>
</my-stripe-list>
</div>
<script>
Vue.component('my-stripe-list', {
/*slot的$index可以传递到父组件中*/
template: `
<div>
<div v-for="(item, index) in items" style="line-height:2.2;" :style="index % 2 === 0 ? 'background:'+oddBgcolor : 'background:'+evenBgcolor">
<slot name="cont" :$index="index"></slot>
</div>
</div>
`,
props: {
items: Array,
oddBgcolor: String,
evenBgcolor: String
}
});
new Vue({
el: '#app2',
data: {
users: [{
id: 1,
name: '张三',
age: 20
},
{
id: 2,
name: '李四',
age: 22
},
{
id: 3,
name: '王五',
age: 27
},
{
id: 4,
name: '张龙',
age: 27
},
{
id: 5,
name: '赵虎',
age: 27
}
]
}
});
</script>
</body>

</html>

这种写法,习惯了element-ui的朋友一定就很熟悉了。

总结:
1 . 使用slot可以在自定义组件内插入原生HTML元素,需要搭配使用name和slot属性,否则多个slot可能会返回重复的HTML元素。
2 . 使用slot-scope可以将slot内部的作用域指向该子组件,否则默认作用域指向调用slot的父组件。

新版本的 v-slot

vue@2.6.x 开始,Vue 为具名和范围插槽引入了一个全新的语法,即我们今天要讲的主角:v-slot 指令。目的就是想统一 slotscope-slot 语法,使代码更加规范和清晰。既然有新的语法上位,很明显,slotscope-slot 也将会在 vue@3.0.x 中彻底的跟我们说拜拜了。而从 vue@2.6.0 开始,官方推荐我们使用 v-slot 来替代后两者。


### 具名插槽 > 实例化一个vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 组件
Vue.component('lv-hello', {
template: `
<div>
<slot name="header"></slot>
<h1>我的天呀</h1>
</div>`
})

new Vue({
el: '#app1',
data: {

}
});

老版本

1
2
3
4
5
6
<div id="app1">
<!-- 老版本使用具名插槽 -->
<lv-hello>
<p slot="header">我是头部</p>
</lv-hello>
</div>

新版本的变化

1
2
3
4
5
6
7
8
  <!-- 新版本使用具名插槽 -->
<lv-hello>
<!-- 注意:这块的 v-slot 指令只能写在 template 标签上面,而不能放置到 p 标签上 -->
<template v-slot:header>
<p>我是头部</p>
</template>
</lv-hello>
</div>

具名插槽的缩写

v-slot: 替换成 #

1
2
3
4
5
6
7
8
9
10
11
<div id="app">
<lv-hello>
<template #header>
<p>我是头部</p>
</template>
<!-- 注意: #号后面必须有参数,否则会报错。即便是默认插槽,也需要写成 #default -->
<template #default>
<p>我是默认插槽</p>
</template>
</lv-hello>
</div>

作用域插槽

所谓作用域插槽,就是让插槽的内容能够访问子组件中才有的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Vue.component('lv-hello', {
data: function () {
return {
firstName: '张',
lastName: '三'
}
},

template: `
<div>
<slot name="header" :firstName="firstName" :lastName="lastName"></slot>
<h1>我的天呀</h1>
</div>
`
})
1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="app">
<!-- 老版本使用具名插槽 -->
<lv-hello>
<p slot="header" slot-scope="hh">我是头部 {{ hh.firstName }} {{ hh.lastName }}</p>
</lv-hello>
<!-- 新版本使用具名插槽 -->
<lv-hello>
<!-- 注意:这块的 v-slot 指令只能写在 template 标签上面,而不能放置到 p 标签上 -->
<template v-slot:header="hh">
<p>我是头部 {{ hh.firstName }} {{ hh.lastName }}</p>
</template>
</lv-hello>
</div>