1 概述
1) 什么是slot
slot可以理解为预留了一个可替换的地方

游戏卡是可以插拔的, 插游戏卡的地方就是一个插槽

思考
游戏卡插槽有什么作用?
再比如, USB接口也可以看成一个插槽
. 可以插入U盘, 硬盘, 鼠标, 键盘...

还有, CPU槽, 内存槽. 他们的存在有什么共同点??
2) 为什么需要slot
通过上面的例子, 我们可以看出
- 通过插不同的游戏卡, 可以玩不同的游戏
- 通过插不同的外设, 可以扩展电脑的功能
- 通过插不同型号的CPU(i3/i5/i7/i9), 可以更换CPU
所以, 插槽最主要的作用是提供扩展性
.
3) Vue中的slot
在Vue开发中, slot主要应用在组件开发中, 通过在组件中预留slot, 实现不同的功能
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<son></son>
</div>
<template id="tmp">
<div>我是子组件</div>
</template>
<script>
const vm = new Vue({
el: '#app',
components: {
son: {
template: '#tmp',
},
},
})
</script>
</body>
</html>
子组件的模板编译后, 会替换<son>
所在的地方

但是, 不管在<son>
中添加任何内容, 都不起作用~
<div id="app">
<son>
<!-- 在子组件里写的内容不会生效 -->
<h2>我是子组件的标题</h2>
</son>
</div>
这样, 子组件的可扩展性就很不好. 如果希望子组件中的内容可以替换怎么办??
在子组件中预留一个插槽
, 通过给子组件传递不同的内容来改变子组件

2 具名插槽
1) 作用
如果需要同时使用多个插槽, 就需要给插槽取名字.
就好比: 主板上同时有CPU槽和内存槽, 如何区分这两个插槽, 不至于把内存插到CPU中
当然, 现实中肯定不会, 但是程序中就需要使用名字区分开
2) 使用
- 在子组件中, 定义具名插槽
- 在引用子组件时, 通过
slot属性
指定要替换的插槽
<div id="app">
<son>
<div slot="cpu">我是CPU</div>
<div slot="memery">我是内存</div>
</son>
</div>
<template id="tmp">
<div>
<slot name="cpu"></slot>
<slot name="memery"></slot>
</div>
</template>
没有指定的内容会全部放到<slot>
中, 也就是默认插槽
<div id="app">
<son>
<div slot="cpu">我是CPU</div>
<div slot="memery">我是内存</div>
<hr />
<div>我是剩余的内容</div>
<p>我也是...</p>
</son>
</div>
<template id="tmp">
<div>
<slot name="cpu"></slot>
<slot name="memery"></slot>
<!-- slot其实也有名字, 名字是default -->
<slot></slot>
<slot name="default"></slot>
</div>
</template>
3 作用域插槽
1) 编译作用域
在Vue编译的过程中, 如果父子组件中定义的相同的状态
, 会不会冲突呢?
如果不会冲突, 具体访问的是哪个状态
呢
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button v-show="isShow">按钮</button>
<son></son>
</div>
<template id="tmp">
<div>
<h3>我是子组件</h3>
<button v-show="isShow">子组件按钮</button>
</div>
</template>
<script>
const vm = new Vue({
el: '#app',
data: {
isShow: false,
},
components: {
son: {
template: '#tmp',
data() {
return {
isShow: true,
}
},
},
},
})
</script>
</body>
</html>
父组件和子组件中都存在isShow
.
- 如果在父模板中使用isShow, 访问的是父组件
data
中的值 - 如果在子模板中使用isShow, 访问的是子组件
data
中的值
通过上述示例, 我们可以发现, 在父组件中是不能直接访问子组件中的状态的.
需求
- 在父模板中可定制子组件的内容
- 同时使用子组件中的数据
2) 为什么需要作用域插槽
为了解决上述问题, 引入了作用域插槽的概念, 其核心是在父模板中访问子组件的数据
示例
<div id="app">
<button v-show="isShow">按钮</button>
<!-- 通过v-slot指令找名字为default的插槽, 并指定prop对象对应default插槽 -->
<son v-slot:default="prop">
<!-- 通过prop对象访问show属性, 相当于访问了子组件的isShow -->
<button v-show="prop.show">子组件按钮</button>
</son>
</div>
<template id="tmp">
<div>
<h3>我是子组件</h3>
<!-- 在slot:default对象中, 定义自定义属性show -->
<slot :show="isShow"></slot>
</div>
</template>
其中, v-slot
可以使用#
简写
<!-- 通过v-slot指令找名字为default的插槽, 并指定prop对象对应default插槽 -->
<son #default="prop">
<!-- 通过prop对象访问show属性, 相当于访问了子组件的isShow -->
<button v-show="prop.show">子组件按钮</button>
</son>
通过同时有多个插槽, 需要借用<template>
语法
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button v-show="isShow">按钮</button>
<!-- 通过v-slot指令找名字为default的插槽, 并指定prop对象对应default插槽 -->
<son>
<template #default="prop">
<!-- 通过prop对象访问show属性, 相当于访问了子组件的isShow -->
<button v-show="prop.show">子组件按钮</button>
</template>
<template #left="left">
<h3>{{left.info.name}}</h3>
</template>
</son>
</div>
<template id="tmp">
<div>
<h3>我是子组件</h3>
<!-- 在slot:default对象中, 定义自定义属性show -->
<slot :show="isShow"></slot>
<slot name="left" :info="stu"></slot>
</div>
</template>
<script>
const vm = new Vue({
el: '#app',
data: {
isShow: false,
},
components: {
son: {
template: '#tmp',
data() {
return {
isShow: true,
stu: {
name: 'xiaoming',
age: 18,
},
}
},
},
},
})
</script>
</body>
</html>
网友评论