(1)插槽内容
像 HTML 元素一样,我们常常需要给组件传递内容
比如在下面的例子中,我们给自定义组件 prompt-info 传入 出错啦
的文本
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<prompt-info>出错啦</prompt-info>
</div>
<script>
Vue.component('prompt-info', {
template: `
<div>
<h3>提示信息</h3>
</div>
`
})
new Vue({
el: '#app'
})
</script>
</body>
</html>
但是,结果并不像我们所想的,出错啦
的提示信息没有显示出来,这时候我们就可以使用 <slot>
解决这个问题
<slot>
就是插槽,也就是说我们需要先在组件中留下一个位置,然后才能在使用的时候把传入的内容放进去
Vue.component('prompt-info', {
template: `
<div>
<h3>提示信息</h3>
<slot></slot>
</div>
`
})
我们还可以为插槽提供默认内容,但是它仅仅会在没有提供内容的时候显示出来
Vue.component('prompt-info', {
template: `
<div>
<h3>提示信息</h3>
<slot>不好意思</slot>
</div>
`
})
在定义好插槽后就可以正常显示传入的内容啦,事实上我们不仅可以传入简单的文本,还可以传入任何模板代码
<div id="app">
<prompt-info>
<span>出错啦</span>
<p>请稍后再试</p>
</prompt-info>
</div>
(2)插槽数据
考虑一个问题,上面我们传入的模板代码中是没有包含数据的,假如现在我们使用数据会发生什么呢?
这里面还有一定的讲究
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<prompt-info>{{ msg }}</prompt-info>
</div>
<script>
Vue.component('prompt-info', {
template: `
<div>
<h3>提示信息</h3>
<slot></slot>
</div>
`
})
new Vue({
el: '#app',
data: {
msg: '服务器离家出走啦 T_T'
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<prompt-info></prompt-info>
</div>
<script>
Vue.component('prompt-info', {
data: function () {
return {
info: '不好意思,请重新再试'
}
},
template: `
<div>
<h3>提示信息</h3>
<slot>{{ info }}</slot>
</div>
`
})
new Vue({
el: '#app'
})
</script>
</body>
</html>
这次没有这么简单,我们先来看一份简单的代码:
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<prompt-info>{{ info }}</prompt-info>
</div>
<script>
Vue.component('prompt-info', {
data: function () {
return {
info: '不好意思,请重新再试'
}
},
template: `
<div>
<h3>提示信息</h3>
<slot></slot>
</div>
`
})
new Vue({
el: '#app'
})
</script>
</body>
</html>
实际上,这份代码不会被正确编译,控制台会输出错误信息:info is not defined
这是因为 父级模板里的所有内容都是在父级作用域中编译的,子模板里的所有内容都是在子作用域中编译的
如果我们希望让插槽内容访问子组件数据,可以怎么做呢?
首先,我们需要在 <slot>
元素上使用 v-bind
指令绑定数据(绑定在 <slot>
元素上的特性称为 插槽 prop)
然后,我们就可以在组件上使用 v-slot
指令获取并使用 插槽 prop
(注意,在这里使用 v-slot
的语法为 v-slot=‘slotProps‘
)
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<prompt-info v-slot='slotProps'>{{ slotProps.info }}</prompt-info>
</div>
<script>
Vue.component('prompt-info', {
data: function () {
return {
defaultInfo: '不好意思,请重新再试',
info: '服务器离家出走啦 T_T'
}
},
template: `
<div>
<h3>提示信息</h3>
<slot v-bind:info='info'>{{ defaultInfo }}</slot>
</div>
`
})
new Vue({
el: '#app'
})
</script>
</body>
</html>
(3)具名插槽
好,下面我们再来考虑另一个问题,当我们需要使用多个插槽时,应该怎么对它们进行区分呢?
答案是在定义的时候使用 name
特性为插槽命名,然后在使用的时候还是使用 v-slot
指令指定插槽
(注意,在这里使用 v-slot
的语法为 v-slot:slotName
,与上面的语法并不冲突)
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<prompt-info>
<template v-slot:header>
<p>服务离家出走啦</p>
</template>
<!-- 没有使用 v-slot 指令指定的元素默认放在 default 插槽 -->
<template>
<p>请稍后再试</p>
</template>
<template v-slot:footer>
<p>不好意思</p>
</template>
</prompt-info>
</div>
<script>
Vue.component('prompt-info', {
template: `
<div>
<h3>提示信息</h3>
<slot name="header"></slot>
<!-- 没有使用 name 特性命名的插槽默认带有名字 default -->
<slot></slot>
<slot name="footer"></slot>
</div>
`
})
new Vue({
el: '#app'
})
</script>
</body>
</html>
同 v-on
和 v-bind
指令一样,Vue 也为 v-slot
指令提供了缩写
<!-- 完整语法 -->
<template v-slot:header>...</template>
<!-- 缩写 -->
<template #header>...</template>
当只有一个默认插槽时,我们可以直接把 v-slot
用在组件上:
Vue.component('prompt-info', {
template: `
<div>
<h3>提示信息</h3>
<slot></slot>
</div>
`
})
<prompt-info v-slot:default="slotProps"></prompt-info>
但是只要出现多个插槽,请始终为所有的插槽使用完整的基于 <template>
的语法:
Vue.component('prompt-info', {
template: `
<div>
<h3>提示信息</h3>
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
</div>
`
})
<prompt-info v-slot:default="slotProps">
<template v-slot:header="slotProps">
<!-- 内容 -->
</template>
<template v-slot:default="slotProps">
<!-- 内容 -->
</template>
<template v-slot:footer="slotProps">
<!-- 内容 -->
</template>
</prompt-info>
原文:https://www.cnblogs.com/wsmrzx/p/11219825.html