1.插槽是什么(举个例子)
(1)匿名插槽
// 父组件 father.vue
<template>
<div>
<div>我是父组件</div>
<sonslot>
<p>能否显示</p>
</sonslot>
</div>
</template>
<script>
import myslot from './sonslot';
export default {
components: {
sonslot
}
}
</script>
<style>
复制代码
// 子组件 sonslot.vue
<template>
<div>
<p>我是子组件</p>
</div>
</template>
<script>
export default {
}
</script>
<style>
复制代码
页面结果:
我是父组件
我是子组件
复制代码
那我们想要把父组件中p标签得内容展示出来怎么办?(只需一步,修改下子组件)
// 子组件 sonslot.vue
<template>
<div>
<p>我是子组件</p>
<slot></slot>
</div>
</template>
<script>
export default {
}
</script>
<style>
复制代码
页面结果:
我是父组件
我是子组件
是否显示
(2)默认插槽
有时我们父组件不在子组件里面写内容,这时候子组件的slot需要准备一个后备内容,也就是默认显示内容。如果父组件不使用插槽(调用子组件不写内容),那么我们就默认显示一个内容
// 父组件 father.vue
<template>
<div>
<div>我是父组件</div>
<sonslot>
</sonslot>
</div>
</template>
<script>
import myslot from './sonslot';
export default {
components: {
sonslot
}
}
</script>
<style>
复制代码
// 子组件 sonslot.vue
<template>
<div>
<p>我是子组件</p>
<slot>我是默认内容</slot>
</div>
</template>
<script>
export default {
}
</script>
<style>
复制代码
页面结果:
我是父组件
我是子组件
我是默认内容
复制代码
由此可以看出当我们调用子组件时,没有写内容,插槽就会显示默认的内容,当我们父组件写内容时,就会显示父组件传过来的内容,不会显示我是默认内容了
插槽优点可以看出:可以实现组件的复用性,就是子组件slot来占个位置,不管外面传什么内容这里照常接收显示,在父组件调用子组件的时候写着组件内部的,会在子组件插槽内显示
2.具名插槽
(1)引用原因,由于匿名插槽的局限性
当我们想使用多个插槽时,也就是我想让我父组件传过来的内容显示在页面的不同位置,如果子组件有多个slot且没有名字就会按照父组件传来的顺序排序,不会按我们想要的位置排序,这就是需要具名插槽的原因,看不懂没关系,看下下面的例子就会明白了。
子组件:
<div class="container">
<header>
<!-- 我们希望把页头放这里 -->
</header>
<main>
<!-- 我们希望把主要内容放这里 -->
</main>
<footer>
<!-- 我们希望把页脚放这里 -->
</footer>
</div>
复制代码
有时候我们需要父组件传过来的内容想要按这种格式展示,所以就需要给子组件插槽起个名字,然后父组件调用子组件然后调用插槽的名字,然后子组件根据名字就会把对应的内容显示到对应的位置
(2)具名插槽例子
//父组件father
<sonslot>
<template v-slot:footer>
<p>我是footer的内容</p>
</template>
<template> //也可以写成v-slot="default"
<p>我是默认的内容,slot不起名字时默认时defauLt</p>
</template>
<template v-slot:header>
<h1>我是header的内容</h1>
</template>
</sonslot>
复制代码
//子组件sonslot
<template>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
复制代码
页面结果:
我是header的内容
我是默认的内容,slot不起名字时默认时defauLt
我是footer的内容
复制代码
总结:我们slot起了名字,然后通过v-slot来调用这个名字,插槽就会对应匹配上,顺序时按照子组件插槽的顺序来排的
3.作用域插槽
(1)作用域例子
//父组件father
<template>
<sonslot>
<template>
{{user.firstName}}
</template>
</sonslot>
</template>
复制代码
//子组件sonslot
<template>
<span>
<slot>{{ user.lastName }}</slot>
</span>
</template>
export default {
data() {
return {
user: {
firstName: 'Jay',
lastName: 'wang'
}
}
}
}
复制代码
页面结果:可能报错了,因为作用域的问题,父组件获取不到子组件的user,父级元素是在父级渲染的,子级元素是子啊子集渲染的,互补干扰
复制代码
那我们父组件想要获取到子组件的数据该如何做呢?
解决作用域问题
//父组件father
<template>
<sonslot>
<template v-slot:header="scope">
{{scope.user.firstName }}
</template>
</sonslot>
</template>
复制代码
//子组件sonslot
<template>
<slot name="header" :user="user">
{{user.lastName }}
</slot>
</template>
export default {
data() {
return {
user: {
firstName: 'Jay',
lastName: 'wang'
}
}
}
}
```js
页面结果:Jay
复制代码
解释:子组件有默认的内容wang,如果不传参默认是wang,子组件user作为slot的一个attribute绑定上去,这被称为插槽prop,现在父级作用域可以在带值得slot提供一个名字也就是scope,scope是我们随便起的名字,随便起名字。
4.解构插槽prop
如上我们随便起了个名字,当然我们也可以不起名字就解构一下,还是用上面得例子只是父组件改变一下
//父组件father
<template>
<sonslot>
<template v-slot:header = {user}>
{{user.firstName }}
</template>
</sonslot>
</template>
复制代码
解释:我们就直接能解构出来user,直接使用
当然我们也可以起别名
//父组件father
<template>
<sonslot>
<template v-slot:header = {user: person}>
{{person.firstName }}
</template>
</sonslot>
</template>
复制代码
你甚至可以定义后备内容,用于插槽 prop 是 undefined 的情形:
//父组件father
<template>
<sonslot>
<template v-slot:header = {user = {firstName:'备用名'}}>
{{user.firstName }}
</template>
</sonslot>
</template>
复制代码
解释:当我们子组件不绑定:user=”user”时,就是undefined,这样我们父组件输出结果就是’备用名’
5.具名插槽缩写
v-slot:header可以缩写成#header
注意:如果我们父组件需要用到子组件的user,即使是没有名的插槽也要#default=”{user}”,不能写成#=”{user}”
注意:默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确,如下
//父组件
<!-- 无效,会导致警告 -->
<sonslot v-slot="scope">
{{ scope.user.firstName }}
<template v-slot:other="otherscope">
这样是不被允许的
</template>
</sonslot>
复制代码
所以要完整写全template语法
// 父组件
<sonslot>
<template v-slot:default="scope">
{{scope.user.firstName }}
</template>
<template v-slot:other="otherscope">
这样是被允许的
</template>
</sonslot>
复制代码
以上是对插槽的总结