💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] # **slot插槽** slot定义在子组件中,相当于留出一个位置。当父组件引用这个子组件时,可以向这个位置插入内容。 ## **1. 匿名插槽(预设插**槽) 在子组件中,由slot标签定义,具有以下特点: **1. 当父组件中,没有特殊指定位置的内容默认放到匿名插槽当中 2. 匿名插槽可以有多个,都会渲染父组件传来的默认内容 3. 当父组件没有传入默认内容时,显示自己的内容** ### 1.1 显示父组件的内容 **1. helloworld.vue** ~~~ <template> <div> <slot>这是子组件的一个预设插槽</slot> </div> </template> <script> export default { name: "HelloWorld", }; </script> ~~~ **2. home.vue** 父组件 ~~~ <template> <div class="home"> <hello-world> 这是父组件传来的内容 </hello-world> </div> </template> <script> // @ is an alias to /src import HelloWorld from "@/components/HelloWorld.vue"; export default { name: "Home", components: { HelloWorld } }; </script> ~~~ 但是,父组件中建议用`<template>`标签传入内容 ~~~ <template> <div class="home"> <hello-world> <template>这是父组件传来的内容</template> </hello-world> </div> </template> ~~~ ![](https://img.kancloud.cn/01/da/01da791c93463e1e14ba0dc8f58134b4_603x172.png) ### 1.2 多个匿名插槽 **1. helloworld.vue** ~~~ <template> <div> <slot>这是子组件的一个预设插槽</slot> <slot>这是子组件的一个预设插槽</slot> <slot>这是子组件的一个预设插槽</slot> </div> </template> <script> export default { name: "HelloWorld", }; </script> ~~~ **2. home.vue** 父组件 ~~~ <template> <div class="home"> <hello-world> <template>这是父组件传来的内容 <br></template> </hello-world> </div> </template> <script> // @ is an alias to /src import HelloWorld from "@/components/HelloWorld.vue"; export default { name: "Home", components: { HelloWorld } }; </script> ~~~ 如下图,多个匿名插槽都被父组件传来的一个内容所替代了 ![](https://img.kancloud.cn/12/96/129697ed81b5527fbc302f3cf5cb91d1_697x290.png) html渲染如下: ![](https://img.kancloud.cn/2e/99/2e9982aceef0c47b92c3675c0927966c_420x247.png) ### 1.3 父组件不传内容时,显示自己 **1. helloworld.vue**同1.2 **2. home.vue**不传内容 ~~~ <template> <div class="home"> <hello-world> </hello-world> </div> </template> ~~~ ![](https://img.kancloud.cn/18/5c/185c0c4b45a6822e0fa8b627f6e0af1e_941x208.png) ## **2. 具名插槽** 相对于匿名插槽,具名插槽有一个名称,用来标识自己,具有以下特点: 1. 可以出现多次,和不同地方 2. 父组件只要匹配了name,就可以渲染 ### **2.1 vue 2.6以前的写法** **1.hellowold.vue** 子组件在slot标签中用name属性声明插槽名称 ~~~ <template> <div> <slot>这是子组件的一个预设插槽</slot> <slot name="header"> 这是具名插槽 </slot> </div> </template> ~~~ **2. home.vue** **在父组件中,使用slot指令指定插槽,slot="插槽名"** 父组件中,在teamplate标签中用`slot="header"`(vue 2.6以前的写法)属性,指定插槽 ~~~ <template> <div class="home"> <hello-world> <template>这是父组件传来的内容 <br></template> <template slot="header">这是父组件传给子组件具名插槽 <br></template> </hello-world> </div> </template> ~~~ ![](https://img.kancloud.cn/e3/55/e3558cba26a50ada7c164e459935cf81_662x216.png) home.vue中去掉slot="header",就会都插入匿名插槽中! ### **2.2 vue 2.6后的写法** **在父组件中,使用v-slot 指定插槽** `v-slot="插槽名"` 或者简写 `#插槽名` **1. hellowold.vue** ~~~ <template> <div> <slot>这是子组件的一个预设插槽</slot> <slot name="header"> 这是具名插槽 </slot> </div> </template> ~~~ **2. home.vue** ~~~ <template> <div class="home"> <hello-world> <template>这是父组件传来的内容 <br></template> <!-- vue 2.6以前 --> <!--<template slot="header">这是父组件传给子组件具名插槽 <br></template>--> <!-- vue 2.6以后写法 --> <template v-slot:header>这是父组件传给子组件具名插槽1 <br></template> </hello-world> </div> </template> ~~~ ![](https://img.kancloud.cn/10/dc/10dcbd0d5d2e5f2144f4e7ee5c9f0d5b_662x241.png) **v-slot指令和v-on等指令一样,也有简写形式** `v-slot:header = #header` ## **3. 作用域插槽** 将slot插槽的所有属性,封装成一个对象(x),父组件在使用子组件时,可以调用这些属性数据-父组件向子组件中的插槽传值(可是是数据或者函数) ### **3.1 使用插槽的属性值** #### **3.1.1 vue 2.6以前的写法** 父组件通过slot-scope或者scope属性(**在vue 2.5.0+ 中slot-scope替代了 scope**) **1.helloworld.vue** ~~~ <template> <div> <slot>这是子组件的一个预设插槽</slot> <slot name="header" data="hello slot" id="110"> 这是具名插槽 </slot> </div> </template> ~~~ **2. home.vue** * slot="header" : 指定name=header的插槽 * slot-scope="slotValue" :对于header插槽,给其属性数据起一个”别名“,这个slotValue是一个对象,包含了slot的所有属性数据:`{ "data": "hello slot", "id": "110" }` ~~~ <template> <div class="home"> <hello-world> <template>这是父组件传来的内容 <br></template> <template slot="header" slot-scope="slotValue"> {{slotValue}} <br> id:{{slotValue.id}} <br> </template> </hello-world> </div> </template> ~~~ ![](https://img.kancloud.cn/0a/a8/0aa8bd67a8b0f746857b649840b86e80_582x239.png) 如图,slotValue包含了header插槽的所有属性数据 #### **3.1.2 vue 2.6以后的写法** v-slot指令,相当于slot和slot-scope的功能集合,slot定位和数据传递 v-slot:插槽名="属性别名" 或者 #插槽名="属性别名" **2. home.vue** ~~~ <template> <div class="home"> <hello-world> <template>这是父组件传来的内容 <br></template> <template v-slot:header="slotValue"> v-slot: {{slotValue}} <br> id:{{slotValue.id}} <br> </template> </hello-world> </div> </template> ~~~ ![](https://img.kancloud.cn/c3/62/c3628972f1420626c1a54f19d2dabb7e_677x267.png) ``` <list :data="listData" class="img-list"> <template scope="scope"> <div class="info"> <p>数据:{{scope}}</p> <p>索引:{{scope.$index}}</p> <p>姓名:{{scope.row.name}}</p> <p>性别:{{scope.row.sex}}</p> </div> </template> </list> ```             ## **4. 案例** ### **4.1 传值** ![](https://img.kancloud.cn/0a/77/0a77100eee0c94ac226cfa86781d887e_688x334.png)    **1. slot-test.vue 子组件** ~~~ <template> <div class="color-list"> <h2>{{ title }}</h2> <div class="list"> <div class="list-item" v-for="(item, index) in items" :key="index"> <slot v-bind="item"></slot> </div> </div> </div> </template> <script> export default { name: "slot-test", props: { title: { type: String, default: 'slot测试' }, items: { type: Array } } } </script> <style scoped> </style> ~~~ 其中:以下产生多个匿名slot ``` <div class="list-item" v-for="(item, index) in items" :key="index"> <slot v-bind="item"></slot> </div> ``` 三个匿名slot ![](https://img.kancloud.cn/7e/db/7edb12d2a368274aac1683464ec71d2f_979x480.png) **2. about.vue** ~~~ <template> <div id="app"> <slot-test :items="colors" title="slot测试"> <template v-slot:default="color"> <div :style="{background: color.hex}">{{ color.name }}</div> </template> </slot-test> </div> </template> <script> import SlotTest from '@/components/slot-test' export default { name: 'app', components: { SlotTest }, data () { return { colors: [ { name: 'Yellow', hex: '#F4D03F', }, { name: 'Green', hex: '#229954' }, { name: 'Purple', hex: '#9B59B6' } ] } } } </script> ~~~ 其中, ``` <template v-slot:default="color"> <div :style="{background: color.hex}">{{ color.name }}</div> </template> ``` v-slot:default="color" :default指定是匿名插槽,也可以不指定。父组件传的值都会再子组件的多个匿名插槽中显示,所有有以下三个颜色的div ![](https://img.kancloud.cn/3a/cc/3acc976f1898ec3544d4b04e77ebad92_617x303.png) ### **4.2 读取值** 子组件通过`v-bind="{ item, form, handleFieldChange, setFieldValue }"`绑定属性数据和函数 ~~~ <slot name="field" v-if="item.slots.ext" v-bind="{ item, form, handleFieldChange, setFieldValue }"> <span>customEditor</span> </slot> setFieldValue(name, value) { this.$set(this.form, name, value); this.handleFieldChange(name, value); }, ~~~ 父组件不但可以使用子组件的值,还可以使用子组件的函数`setFieldValue` ~~~ <template v-slot:field="{ form, item, setFieldValue }"> <div> <el-input :value="form.file" @input="setFieldValue(item.field.name, $event)"> <el-button slot="append" @click="uploadBtn">选择软件包</el-button> </el-input> <input @change="changeFile(form, item.field.name,setFieldValue)" type="file" style="display: none;" class="fileInput"/> </div> </template> ~~~ ## 5. 总结 vue2.6以后使用v-slot代替slot和slot-scope(scope),例如: ~~~ v-slot:header="slotValue" ~~~ 等价于 ~~~ slot="header" slot-scope="slotValue"> ~~~