一、插槽slot的基本使用
组件的插槽也是为了让我们封装的组件更加具有扩展性。让使用者可以决定组件内部的一些内容到底展示什么。
栗子:
上述的图片展示的组件结构一样,但是内容不同,若每次都单独重写的话无疑工作量巨大,但是使用插槽就可以先把框架搭好,里面的内容就可根据实际需求进行修改,这样就减少了重复代码的书写。
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="../js/vue.js"></script>
<template id="cpn">
<div>
<h2>哈哈哈</h2>
<p>我是组件</p>
<slot><button>我是默认值</button></slot><!--就相当于再这个组件中预留一个为位置作为扩展,可以在这个标签中添加内容作为默认值
在使用这个组件时如果没有指定内容就使用默认值
-->
</div>
</template>
<!--有时需要再增添些内容向组件中,这时候就需要插槽了-->
<div id="app">
<!--现在我只想向第一个组件中加一个按钮,如下写法-->
<cpn><button>按钮</button></cpn>
<cpn><span>哈哈</span></cpn>
<cpn></cpn>
<cpn><a href="#">走你</a></cpn>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'helloWorld!'
},
components:{
cpn:{
template:'#cpn'
}
}
});
</script>
</body>
</html>
二、具名插槽的使用
组件用到多个插槽时该怎末匹配替换插槽,使用name属性,而且使用时有限替换没有name属性值的插槽
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="../js/vue.js"></script>
<template id="cpn">
<!--组件用到多个插槽时该怎末匹配替换插槽,使用name属性,而且使用时有限替换没有name属性值的插槽-->
<div>
<slot name="left">左边</slot>
<slot name="center">中间</slot>
<slot name="right">右边</slot>
<slot>hahaha</slot>
</div>
</template>
<div id="app">
<cpn>我替换的是没有name的插槽</cpn>
<cpn><span slot="center">我替换的是中间的</span></cpn>
<cpn><span slot="left">我替换的是左边的</span></cpn>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'helloWorld!'
},
components:{
cpn:{
template:'#cpn'
}
}
});
</script>
</body>
</html>
三、作用域插槽
理解:父组件替换插槽的标签,但是内容由子组件来提供。
我们先提一个需求:
- 子组件中包括一组数据,比如:pLanguages: ['JavaScript', 'Python', 'Swift', 'Go', 'C++']
- 需要在多个界面进行展示:某些界面是以水平方向一一展示的,某些界面是以列表形式展示的,某些界面直接展示一个数组
内容在子组件,希望父组件告诉我们如何展示,怎么办呢?
这里利用slot作用域插槽就可以了
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="../js/vue.js"></script>
<!--有时父组件展示子组件内容,但是想换其他方式来展示,这就需要拿到子组件中的数据来展示,这个方法现在有改动-->
<template id="cpn">
<div>
<slot :data="pLanguages">
<ul>
<li v-for="item in pLanguages">{{item}}</li>
</ul>
</slot>
</div>
</template>
<div id="app">
<!--现在我有个需求,让这三个以不同的方式来展示列表-->
<!--这里我想用子组件中的pLanguage,这里就要获取到这个属性了-->
<cpn>
<template slot-scope="slot">
<span v-for="item in slot.data">{{item}}--</span>
<br>
<span>{{slot.data.join("||")}}</span>
</template>
</cpn>
<!-- -->
<cpn></cpn>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'helloWorld!'
},
components: {
cpn: {
template: '#cpn',
data() {
return {
pLanguages: ['JavaScript', 'C++', 'C#', 'Go', 'python']
}
}
}
}
});
</script>
</body>
</html>
我们通过获取到slot属性,在通过slot.data就可以获取到刚才我们传入的data了,这其实和之前说的组件通信类似,可以这么理解。