1 概述
1) 什么是slot
slot可以理解為預(yù)留了一個可替換的地方

游戲卡是可以插拔的, 插游戲卡的地方就是一個插槽

思考
游戲卡插槽有什么作用?
再比如, USB接口也可以看成一個插槽. 可以插入U盤, 硬盤, 鼠標(biāo), 鍵盤...

還有, CPU槽, 內(nèi)存槽. 他們的存在有什么共同點??
2) 為什么需要slot
通過上面的例子, 我們可以看出
- 通過插不同的游戲卡, 可以玩不同的游戲
- 通過插不同的外設(shè), 可以擴展電腦的功能
- 通過插不同型號的CPU(i3/i5/i7/i9), 可以更換CPU
所以, 插槽最主要的作用是提供擴展性.
3) Vue中的slot
在Vue開發(fā)中, slot主要應(yīng)用在組件開發(fā)中, 通過在組件中預(yù)留slot, 實現(xiàn)不同的功能
示例
<!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>中添加任何內(nèi)容, 都不起作用~
<div id="app">
<son>
<!-- 在子組件里寫的內(nèi)容不會生效 -->
<h2>我是子組件的標(biāo)題</h2>
</son>
</div>
這樣, 子組件的可擴展性就很不好. 如果希望子組件中的內(nèi)容可以替換怎么辦??
在子組件中預(yù)留一個插槽, 通過給子組件傳遞不同的內(nèi)容來改變子組件

2 具名插槽
1) 作用
如果需要同時使用多個插槽, 就需要給插槽取名字.
就好比: 主板上同時有CPU槽和內(nèi)存槽, 如何區(qū)分這兩個插槽, 不至于把內(nèi)存插到CPU中
當(dāng)然, 現(xiàn)實中肯定不會, 但是程序中就需要使用名字區(qū)分開
2) 使用
- 在子組件中, 定義具名插槽
- 在引用子組件時, 通過
slot屬性指定要替換的插槽
<div id="app">
<son>
<div slot="cpu">我是CPU</div>
<div slot="memery">我是內(nèi)存</div>
</son>
</div>
<template id="tmp">
<div>
<slot name="cpu"></slot>
<slot name="memery"></slot>
</div>
</template>
沒有指定的內(nèi)容會全部放到<slot>中, 也就是默認(rèn)插槽
<div id="app">
<son>
<div slot="cpu">我是CPU</div>
<div slot="memery">我是內(nèi)存</div>
<hr />
<div>我是剩余的內(nèi)容</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編譯的過程中, 如果父子組件中定義的相同的狀態(tài), 會不會沖突呢?
如果不會沖突, 具體訪問的是哪個狀態(tài)呢
示例
<!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中的值
通過上述示例, 我們可以發(fā)現(xiàn), 在父組件中是不能直接訪問子組件中的狀態(tài)的.
需求
- 在父模板中可定制子組件的內(nèi)容
- 同時使用子組件中的數(shù)據(jù)
2) 為什么需要作用域插槽
為了解決上述問題, 引入了作用域插槽的概念, 其核心是在父模板中訪問子組件的數(shù)據(jù)
示例
<div id="app">
<button v-show="isShow">按鈕</button>
<!-- 通過v-slot指令找名字為default的插槽, 并指定prop對象對應(yīng)default插槽 -->
<son v-slot:default="prop">
<!-- 通過prop對象訪問show屬性, 相當(dāng)于訪問了子組件的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對象對應(yīng)default插槽 -->
<son #default="prop">
<!-- 通過prop對象訪問show屬性, 相當(dāng)于訪問了子組件的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對象對應(yīng)default插槽 -->
<son>
<template #default="prop">
<!-- 通過prop對象訪問show屬性, 相當(dāng)于訪問了子組件的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>