什么是插槽?
在 vue 中通过 slot 可以向组件中指定位置插入内容.
正常情况下调用一个组件 < com-form></com-form > 的时候, 组件显示的内容为 com-input 组件中模板的内容. 可是想在调用组件的时候给组件添加内容, 该怎么办呢?
- // 父组件
- <com-form>
- <span > 我是插槽内容</span>
- </com-form>
- // 子组件 com-form
- <templete>
- <div>
我是组件内容
- <slot>
- </slot>
- </div>
- </templete>
- // 显示 --- 我是组件内容 我是插槽内容
插槽的通俗理解就是是 "占坑", 在组件模板中占好了位置, 当使用该组件标签时候, 组件标签里面的内容就会自动填坑 (替换组件模板中 < slot > 位置), 当插槽也就是坑 < slot name="mySlot"> 有命名时, 组件标签中使用属性 slot="mySlot" 的元素就会替换该对应位置内容.
一, 单个插槽 / 默认插槽 / 匿名插槽
首先是单个插槽, 单个插槽是 vue 的官方叫法, 但是其实也可以叫它默认插槽, 或者与具名插槽相对, 我们可以叫它匿名插槽. 因为它不用设置 name 属性.
单个插槽可以放在组件任意位置, 但是一个组件有且只能有一个单个插槽, 相对应的, 具名插槽就可以有很多个.
父组件:
- <template>
- <div class="father">
- <h3 > 这里是父组件</h3>
- <child>
- <div class="tmpl">
- <span > 菜单 1</span>
- <span > 菜单 2</span>
- <span > 菜单 3</span>
- <span > 菜单 4</span>
- <span > 菜单 5</span>
- <span > 菜单 6</span>
- </div>
- </child>
- </div>
- </template>
子组件:
- <template>
- <div class="child">
- <h3 > 这里是子组件</h3>
- <slot></slot>
- </div>
- </template>
最终显示
二, 具名插槽
匿名插槽没有 name 属性, 所以是匿名插槽, 那么, 插槽加了 name 属性, 就变成了具名插槽. 具名插槽可以在一个组件中出现 N 次, 出现在不同的位置. 下面的例子, 就是一个有两个具名插槽和单个插槽的组件, 这三个插槽被父组件用同一套 CSS 样式显示了出来, 不同的是内容上略有区别.
父组件:
- <template>
- <div class="father">
- <h3 > 这里是父组件</h3>
- <child>
- <div class="tmpl" slot="up">
- <span > 菜单 1</span>
- <span > 菜单 2</span>
- <span > 菜单 3</span>
- <span > 菜单 4</span>
- <span > 菜单 5</span>
- <span > 菜单 6</span>
- </div>
- <div class="tmpl" slot="down">
- <span > 菜单 - 1</span>
- <span > 菜单 - 2</span>
- <span > 菜单 - 3</span>
- <span > 菜单 - 4</span>
- <span > 菜单 - 5</span>
- <span > 菜单 - 6</span>
- </div>
- <div class="tmpl">
- <span > 菜单 ->1</span>
- <span > 菜单 ->2</span>
- <span > 菜单 ->3</span>
- <span > 菜单 ->4</span>
- <span > 菜单 ->5</span>
- <span > 菜单 ->6</span>
- </div>
- </child>
- </div>
- </template>
子组件:
- <template>
- <div class="child">
- // 具名插槽
- <slot name="up"></slot>
- <h3 > 这里是子组件</h3>
- // 具名插槽
- <slot name="down"></slot>
- // 匿名插槽
- <slot></slot>
- </div>
- </template>
最终显示
三, 作用域插槽
匿名插槽和具名插槽都是在父组件中定义内容与样式, 子组件只是负责放在哪. 但是如果子组件提供数据, 那这样的话需要子组件的 < slot > 把数据传递给父组件, 父组件只需要提供样式即可.
子组件 child
- <template>
- <div class="child">
- <h3 > 这里是子组件</h3>
- // 作用域插槽
- <slot :data="data"></slot>
- </div>
- </template>
- export default {
- data: function(){
- return {
- data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
- }
- }
- }
父组件
- <template>
- <div class="father">
- <h3 > 这里是父组件</h3>
- <!-- 第一次使用: 用 flex 展示数据 -->
- <child>
- <template slot-scope="user">
- <div class="tmpl">
- <span v-for="item in user.data">{{item}}</span>
- </div>
- </template>
- </child>
- <!-- 第二次使用: 用列表展示数据 -->
- <child>
- <template slot-scope="user">
- <ul>
- <li v-for="item in user.data">{{item}}</li>
- </ul>
- </template>
- </child>
- <!-- 第三次使用: 直接显示数据 -->
- <child>
- <template slot-scope="user">
- {{user.data}}
- </template>
- </child>
- <!-- 第四次使用: 不使用其提供的数据, 作用域插槽退变成匿名插槽 -->
- <child>
我就是模板
- </child>
- </div>
- </template>
最终展示
四, v-slot
在 2.6.0 中, 我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令). 它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍在文档中的 attribute.
- // 根组件
- <template>
- <div>
- <mo>
- <template v-slot:header="slotProps">
- <h1>{{slotProps.header + ' ' + msg}}</h1>
- </template>
- <p>A paragraph for the main content.</p>
- <p>And another one.</p>
- <template v-slot:footer>
- <p>Here's some contact info</p>
- </template>
- </mo>
- </div>
- </template>
- <script>
- import mo from './module.vue'
- export default {
- components: {
- mo
- },
- data() {
- return {
- msg: '这是根组件的消息'
- }
- }
- }
- </script>
- // 子组件
- <template>
- <div>
- --header start--
- <header>
- <slot name="header" :header="header"></slot>
- </header>
- --header over--
- <div></div>
- --default start--
- <slot></slot>
- --default over--
- <div></div>
- --footer start--
- <footer>
- <slot name="footer"></slot>
- </footer>
- --dooter over--
- </div>
- </template>
- <script>
- export default {
- data() {
- return {
- header: '来自子组件的头部消息'
- }
- }
- }
- </script>
- <style scoped>
- </style>
最终显示
来源: http://www.jianshu.com/p/33535c099b09