Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口。
插槽(2.6版本以下内容,存在不推荐,即将废弃) 新版本插槽请看文章后半段
在组件中使用 <slot></slot> 标签来标记一个插槽,在调用的时候,调用标签内的内容会自动替换 slot 标签。
TIP:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
<!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>Vue 插槽</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<zj>
<div>这里的内容将会替换slot标签</div>
</zj>
</div>
<template id="zj">
<div>
下面是一个插槽
<slot>这里是插槽的默认内容,如果没有传内容,就会显示默认内容</slot>
</div>
</template>
<script>
const app=new Vue({
el:"#app",
data:{},
components:{
zj:{
template:'#zj'
}
}
});
</script>
</body>
</html>
我们可以给插槽起个名字,只替换指定名称的插槽。
<!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>Vue 具名插槽</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<zj>
<div slot="s1">插槽1的值变了</div>
<div slot="s3">插槽3的值变了</div>
<div>不指定名称,替换默认插槽</div>
</zj>
</div>
<template id="zj">
<div>
第一个插槽
<slot name="s1">第一个插槽默认值</slot>
第二个插槽
<slot name="s2">第二个插槽默认值</slot>
第三个插槽
<slot name="s3">第三个插槽默认值</slot>
第四个插槽
<slot>默认插槽默认值</slot>
</div>
</template>
<script>
const app=new Vue({
el:"#app",
data:{},
components:{
zj:{
template:'#zj'
}
}
});
</script>
</body>
</html>
子组件数据无法直接在父组件中使用,可以通过 slot-scope 来传递子组件数据给父组件。
在子组件 slot 中通过绑定数据的形式传送给父组件,如组件通过 slot-scope 来接收子组件数据
<!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>Vue 作用域插槽</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<zj>
<template slot-scope="data">
这里收到了来自子组件的数据1:{{data.csname}}
</template>
<template slot="cc1" slot-scope="data1">
这里收到了来自子组件具名插槽的数据2:{{data1.csname}}
</template>
</zj>
</div>
<template id="zj">
<div>
下面是个插槽
<slot :csname="name">插槽默认值</slot>
<slot name="cc1" :csname="name">插槽默认值cc1</slot>
</div>
</template>
<script>
const app=new Vue({
el:"#app",
data:{},
components:{
zj:{
template:'#zj',
data(){
return {
name:"曾子丹",
}
}
}
}
});
</script>
</body>
</html>
插槽(2.6以后版本,推荐)
在 2.6.0 以后,vue为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除的属性。
插槽的基础使用未发生变化.
<div id="app">
<zj>
<div>这里的内容将会替换slot标签</div>
</zj>
</div>
<template id="zj">
<div>
下面是一个插槽
<slot>这里是插槽的默认内容,如果没有传内容,就会显示默认内容</slot>
</div>
</template>
<script>
const app=new Vue({
el:"#app",
data:{},
components:{
zj:{
template:'#zj'
}
}
});
</script>
2.6以后版本在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称。
TIP:2.6版本以上虽然也支持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>Vue 具名插槽2.6</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<zj>
<template v-slot:s1>插槽1的值变了</template>
<template v-slot:s3>插槽3的值变了</template>
默认值还是会替换没有命名的插槽内容
</zj>
</div>
<template id="zj">
<div>
第一个插槽<br>
<slot name="s1">第一个插槽默认值</slot><br>
第二个插槽<br>
<slot name="s2">第二个插槽默认值</slot><br>
第三个插槽<br>
<slot name="s3">第三个插槽默认值</slot><br>
第四个插槽<br>
<slot>默认插槽默认值</slot><br>
</div>
</template>
<script>
const app=new Vue({
el:"#app",
data:{},
components:{
zj:{
template:'#zj'
}
}
});
</script>
</body>
</html>
TIP:默认插槽在接收数据时,要使用名称default来接收。也可以使用 v-slot="data" 的形式接收数据
<!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>Vue 作用域插槽2.6</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<zj>
<template v-slot:cc1="data">
这里收到了来自子组件具名插槽的数据:{{data.csname}}
</template>
<template v-slot:default="data2">
默认插槽获取子组件数据方式:{{data2.csname2}}
</template>
</zj>
</div>
<template id="zj">
<div>
下面是个插槽<br>
<slot name="cc1" :csname="name">插槽默认值cc1</slot><br>
<slot :csname2="name">默认插槽内容</slot><br>
</div>
</template>
<script>
const app=new Vue({
el:"#app",
data:{},
components:{
zj:{
template:'#zj',
data(){
return {
name:"曾子丹",
}
}
}
}
});
</script>
</body>
</html>
v-slot 属性必须用在 template 标签上,否则报错,但是如果有且仅有一个默认插槽时,组件的标签才可以被当作插槽的模板来使用,同时不带参数的 v-slot 被假定对应默认插槽。注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确。如果想同时使用多个插槽,就必须使用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>Vue 独占插槽</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<zj v-slot="data">
这里收到了来自子组件具名插槽的数据:{{data.csname}}
</zj>
</div>
<template id="zj">
<div>
下面是个独占默认插槽<br>
<slot :csname="name">默认插槽内容</slot><br>
</div>
</template>
<script>
const app=new Vue({
el:"#app",
data:{},
components:{
zj:{
template:'#zj',
data(){
return {
name:"曾子丹",
}
}
}
}
});
</script>
</body>
</html>
动态指令参数也可以用在 v-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>Vue 动态插槽名</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<zj v-slot:[ccname]="data">
这里收到了来自子组件具名插槽的数据:{{data.csname}}
</zj>
</div>
<template id="zj">
<div>
下面是个独占默认插槽<br>
<slot name="abc" :csname="name">默认插槽内容</slot><br>
</div>
</template>
<script>
const app=new Vue({
el:"#app",
data:{
ccname:'abc'
},
components:{
zj:{
template:'#zj',
data(){
return {
name:"曾子丹",
}
}
}
}
});
</script>
</body>
</html>
跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 # 。例如 v-slot:header 可以被重写为 #header:
TIP:只有具名插槽才能使用缩写,默认插槽也需要使用 #default 来调用,直接写 # 会报错。
<!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>Vue 具名插槽的缩写</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<zj>
<template #abc="data">
这里收到了来自子组件具名插槽的数据:{{data.csname}}
</template>
<template #default>
默认插槽的内容被替换了
</template>
</zj>
</div>
<template id="zj">
<div>
<slot name="abc" :csname="name">默认插槽内容</slot><br>
<slot>我只是个默认插槽</slot>
</div>
</template>
<script>
const app=new Vue({
el:"#app",
data:{},
components:{
zj:{
template:'#zj',
data(){
return {
name:"曾子丹",
}
}
}
}
});
</script>
</body>
</html>