slot插槽
-
为什么要使用slot插槽
- 组件的插槽是为了让我们封装的组件更加具有扩展性
- 让使用者可以灵活地决定组件内部的内容到底展示什么
- 网页和网页间每一个组件有很多的区别, 也有很多共性, 如果我们为每一个网页都去单独地封装一个组件是不合适的, 所以我们需要slot插槽
-
如何封装一个灵活的组件
- 将共性(相同的地方)抽取放到组件中, 将不同的地方暴露为插槽
- 预留了插槽, 就可以让使用者根据自己的需求, 决定插槽内的内容
-
slot的基本使用
- 在子组件中, 用特殊的元素标签slot就可以为子组件创建一个插槽
- 插槽中插入的内容是什么由父组件来决定
-
slot的注意点
- slot的默认值, 在父组件中没有写入要插入的内容的话, 就会默认显示slot的默认值
- 如果父组件中一次性插入多个元素, 那么所有的元素都会进行替换
<body>
<div id="app">
<!-- 在组件的标签中填入要替换slot占位的元素 -->
<cpn><button>按钮</button></cpn>
<cpn><span>我是span</span></cpn>
<!-- 如果一次性填入多个替换的元素, 所有的替换元素都会进行替换 -->
<cpn>
<i>我是i</i>
<p>我是替换的p</p>
<span>我是替换的span</span>
</cpn>
<!-- 如果标签内没有填入要替换的slot占位的元素, slot会使用默认的元素替换 -->
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是h2</h2>
<p>我是p</p>
<!-- 在组件中使用solt标签占位 -->
<!-- 在slot标签中填入默认的元素, 默认元素会在子组件标签没有填入替换的元素的时候显示出来 -->
<slot><button>我是默认的按钮</button></slot>
</div>
</template>
<script>
const app = new Vue({
el: "#app",
components: {
cpn: {
template: "#cpn"
}
}
})
</script>
</body>
具名slot的使用
- 当子组件的功能复杂时, 子组件的插槽可能由很多个, 那么在父组件中给插槽插入内容的时候, 如何区分插入的是哪一个插槽呢?
- 此时需要给插槽起一个名字, 添加一个name属性
- 然后在插入的元素中添加slot属性, 值为需要替换的插槽的name值
<body>
<div id="app">
<!-- 使用子组件的时候, 给需要替换的添加slot属性, 值为需要替换的slot标签的name值, 即可定向替换元素 -->
<cpn><button slot="center">替换中间的</button></cpn>
</div>
<template id="cpn">
<div>
<!-- 给插槽标签添加name属性 -->
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
</div>
</template>
<script>
const app = new Vue({
el: "#app",
components: {
cpn: {
template: "#cpn"
}
}
})
</script>
</body>
编译的作用域
- 在组件模板中使用的所用东西, 来自该组件
- 官方的准则: 父组件模板的所有东西都会在父级作用域内编译, 子级组件模板的所有东西都会在子级作用域内编译
<body>
<div id="app">
<!-- 在这里使用的isShow数据是来自根组件的,因为这里是app根组件 -->
<cpn v-show="isShow"></cpn>
</div>
<template id="cpn">
<div>
<!-- 在这里使用的isShow数据是来自cpn组件的, 因为这里是cpn子组件 -->
<h2>我是标题</h2>
<p>我是内容</p>
<span v-show="isShow">我是span</span>
</div>
</template>
<script>
const app = new Vue({
el: "#app",
data: {
isShow: true
},
components: {
cpn: {
template: "#cpn",
data() {
return {
isShow: false
}
}
}
}
})
</script>
</body>
作用域插槽的使用
- 总结起来就是一句话, 父组件替换插槽的标签, 但是内容由子组件来提供
- 就是父组件来决定如何渲染子组件的内容
- 如何使用作用域插槽
- 子组件模板中, 通过给slot标签添加v-bind:自定义名称=“想要暴露的数据” 属性来发送子组件的数据
- 在父组件中的子组件标签中嵌套一个一个template标签(Vue2.5.x以后可以使用其他的标签比如div等)
- 在这个template标签中添加 slot-scope=“也是自定义的名字” 来接收slot标签发送的数据
- 在template标签内就可以使用子组件发送来的数据了
<body>
<div id="app">
<!-- 默认是按照子组件模板中设定的模板渲染 -->
<cpn></cpn>
<!-- 如果想在父组件中其他的形式展示子组件的内容, 就要使用作用域插槽 -->
<cpn>
<!-- 在子组件标签中嵌套一个template标签(Vue2.5.x以后可以使用其他的标签比如div等) -->
<!-- 在该标签中添加 slot-scope="也是自定义的名字" 来接收slot标签发送的数据 -->
<template slot-scope="acceptdata">
<!-- 在这个标签内就可以使用子组件发送来的数据了 -->
<!-- <span v-for="item in acceptdata.cpndata"> {{item}} - </span> -->
<span>{{acceptdata.cpndata.join(" - ")}}</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<!-- 通过slot标签中添加 v-bind:自定义名称="想要暴露的数据" 属性来发送子组件的数据 -->
<slot :cpndata="pLanguages">
<ul>
<li v-for="item in pLanguages">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script>
const app = new Vue({
el: "#app",
components: {
cpn: {
template: "#cpn",
data() {
return {
pLanguages: ["JavaScript", "C++", "C#", "python"]
}
}
}
}
})
</script>
</body>