Vue插槽(slot)详解与使用方法

简介: Vue插槽(slot)详解与使用方法

插槽:简单理解就是组件内部留一个或多个的插槽位置,可供组件传对应的模板代码进去。插槽的出现,让组件变的更加灵活。

1. 匿名插槽

父组件

// home.vue
<template>
  <div class="home">
    <footerComponent>
      <p>我是匿名插槽</p>
    </footerComponent>
  </div>
</template>
<script>
import footerComponent from '@/components/footerComponent.vue'
export default {
  components: {
    footerComponent,
  }
}
</script>

子组件

// footerComponent.vue
<template>
  <div>
    <h1>子组件</h1>
    <slot></slot> //  替换为 <p>我是匿名插槽</p>
  </div>
</template>

2020062310470442.png

1.2 后备内容

有时为一个插槽设置具体的后备 (也就是默认的) 内容是很有用的,它只会在没有提供内容的时候被渲染。

父组件

// home.vue
<template>
  <div class="home">
    <footerComponent></footerComponent>
  </div>
</template>
<script>
import footerComponent from '@/components/footerComponent.vue'
export default {
  components: {
    footerComponent,
  }
}
</script>

子组件

// footerComponent.vue
<template>
  <div>
    <h1>子组件</h1>
    <slot>
      <p>我是后补内容</p>
    </slot>
  </div>
</template>

2020062310470442.png

2. 具名插槽

顾名思义就是带名字的插槽,假如需要在组件内部预留多个插槽位置,就需要为插槽定义名字,指定插入的位置。

Vue 2.6.0+ 版本,使用v-slot替代slot 和 slot-scope。

注意点:

1.具名插槽的内容必须使用模板< template ></ template >包裹;

2.不指定名字的模板插入匿名插槽中,推荐使用具名插槽,方便代码追踪且直观清楚;

3.匿名插槽具有隐藏的名字"default;"

2.1 具名插槽的缩写

跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。

例如 v-slot:header 可以被重写为 #header;

然而,和其它指令一样,该缩写只在其有参数的时候才可用。这意味着以下语法是无效的:

// 这样会触发一个警告 
<current-user #="{ user }">
  {{ user.firstName }}
</current-user>

如果你希望使用缩写的话,你必须始终以明确插槽名取而代之:

<current-user #default="{ user }">
  {{ user.firstName }}
</current-user>

2.2 动态插槽名

动态指令参数也可以用在 v-slot 上,来定义动态的插槽名

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</base-layout>

父组件

// 现在 <template>元素中的所有内容都将会被传入相应的插槽。
// 任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容。
<template>
  <div class="home">
    <footerComponent>
      <template v-slot:header>
        <h2>header</h2>
      </template>
      <template v-slot:[mybody]>
        <h3>动态插槽名</h3>
      </template>
      <p>内容</p>
      <template #footer>
        <h2>footer</h2>
      </template>
    </footerComponent>
  </div>
</template>
<script>
import footerComponent from '@/components/footerComponent.vue'
export default {
  data(){
    return{
      mybody:'body',
    }
  },
  components: {
    footerComponent,
  }
}
</script>

子组件

<template>
  <div class="footerComponent">
    <h1>子组件</h1>
    <slot name="header"></slot>
    <slot name="body"></slot>
    <slot><p>我是后补内容</p></slot>   //  等价于 <slot name="default"></slot>
    <slot name="footer"></slot>
  </div>
</template>
<style scoped lang="stylus">
.footerComponent
  width 100%
  height 200px
  background-color pink
</style>

2020062310470442.png

3. 作用域插槽

3.1 父传子

父组件

<template>
  <div class="home">
    <headerComponent :title="myName">
      <template #header>
        <h2>父组件</h2>
      </template>
    </headerComponent>
  </div>
</template>
<script>
import headerComponent from '@/components/headerComponent.vue'
export default {
  data(){
    return{
      myName:'我是',
    }
  },
  components: {
    headerComponent,
  }
}
</script>

子组件

<template>
  <div class="headerComponent">
    <slot name="header"></slot>
  <div class="childName">{{title}}子组件</div>
  </div>
</template>
<script>
export default {
  props: {
    title:String
  }
}
</script>
<style scoped lang="stylus">
.childName
  color red
  font-size 20px
</style>

2020062310470442.png

父组件传递的插槽内容是由子组件编译的,插槽作用域由子组件决定。

所以如果需要动态修改插槽的内容,就需要子组件传参给父组件。

3.2 子传父

父组件传参给子组件,props接收后,插槽slot再通过绑定属性传递参数返回给父组件,不管是模板代码还是数据,控制权完全掌握在父组件手里。

第一种方式

父组件

<template>
  <div class="home">
    <footerComponent :myLayout="layout">
      <template v-slot:header="headerSlotProps">
        <h2>{{headerSlotProps.header}}</h2>
      </template>
      <template v-slot="slotProps">
        <p>{{slotProps.content}}</p>
      </template> 
      <template #footer="slotProps">
        <h2>{{slotProps.footer}}</h2>
      </template>
    </footerComponent>
  </div>
</template>
<script>
import footerComponent from '@/components/footerComponent.vue'
export default {
  data(){
    return{
      layout:{
        header:'头部',
        content:'内容',
        footer:'脚部'
      },
    }
  },
  components: {
    footerComponent
  }
}
</script>

子组件

<template>
  <div class="footerComponent">
    <h1>子组件</h1>
    <slot name="header" :header="myLayout.header"></slot>
    <slot :content="myLayout.content"><p>我是后补内容</p></slot>
    <slot name="footer" :footer="myLayout.footer"></slot>
  </div>
</template>
<script>
export default {
  props: {
    myLayout:Object
  }
}
</script>
<style scoped lang="stylus">
.footerComponent
  width 100%
  height 250px
  background-color pink
</style>

2020062310470442.png

第二种方式
子组件通过属性 <slot :自定义属性名 = '值'></slot>,将自己内部的原始类型给到父组件;
父组件 <template slote-scope='自定义接收'></template>;
子组件 slot 除了要占个位置还要传递参数,父组件 slote-scope 负责接收参数;

父组件

<template>
  <div class="home">
    <childComponent :list="provinces">
      <template slot-scope="slotProps">
        <h4 v-for="city in slotProps.cities" :key="city.id" >
          城市: {{city.name}}
        </h4>
      </template>
    </childComponent>
  </div>
</template>
<script>
import childComponent from './itemComponent.vue'
export default {
  data(){
    return{
      provinces:[
        {
          id:1,
          name:'江苏',
          cities:[
            {id:11,name:'南京'},
            {id:12,name:'苏州'}
          ]
        },{
          id:2,
          name:'湖北',
          cities:[
            {id:21,name:'武汉'},
            {id:22,name:'鄂州'}
          ]
        },
      ]
    }
  },
  components: {
    childComponent
  }
}
</script>
-------------------------第一种方式实现,其余部分不变-------------------------------
<template>
  <div class="home">
    <childComponent :list="provinces">
      <template v-slot="slotProps">
        <h4 v-for="city in slotProps.cities" :key="city.id" >
          城市: {{city.name}}
        </h4>
      </template>
    </childComponent>
  </div>
</template>

子组件

<template>
  <div class="footerComponent">
    <div v-for="item in list" :key="item.id">
      <h2>省份:{{item.name}}</h2> 
      <slot :cities="item.cities"></slot>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    list:{
      type: Array,
      default: function(){
        return []
      }
    }
  }
}
</script>

image.png

参考文章(侵删)





相关文章
|
9月前
|
JavaScript
Vue中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
751 2
|
8月前
|
缓存 JavaScript
vue中的keep-alive问题(2)
vue中的keep-alive问题(2)
630 137
|
11月前
|
人工智能 JSON JavaScript
VTJ.PRO 首发 MasterGo 设计智能识别引擎,秒级生成 Vue 代码
VTJ.PRO发布「AI MasterGo设计稿识别引擎」,成为全球首个支持解析MasterGo原生JSON文件并自动生成Vue组件的AI工具。通过双引擎架构,实现设计到代码全流程自动化,效率提升300%,助力企业降本增效,引领“设计即生产”新时代。
762 1
|
11月前
|
JavaScript 安全
在 Vue 中,如何在回调函数中正确使用 this?
在 Vue 中,如何在回调函数中正确使用 this?
535 0
|
JavaScript
初识 Vue(19)---(Vue 中使用插槽(slot))
Vue 中使用插槽(slot) 案例:子组件中的一部分内容是根据父组件传递来的 DOM 来进行显示 Vue 中使用插槽(slot) Vue.
1436 0
|
12月前
|
人工智能 JavaScript 算法
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
1186 0
|
JavaScript
vue实现任务周期cron表达式选择组件
vue实现任务周期cron表达式选择组件
1479 4
|
12月前
|
JavaScript UED
用组件懒加载优化Vue应用性能
用组件懒加载优化Vue应用性能
|
JavaScript 数据可视化 前端开发
基于 Vue 与 D3 的可拖拽拓扑图技术方案及应用案例解析
本文介绍了基于Vue和D3实现可拖拽拓扑图的技术方案与应用实例。通过Vue构建用户界面和交互逻辑,结合D3强大的数据可视化能力,实现了力导向布局、节点拖拽、交互事件等功能。文章详细讲解了数据模型设计、拖拽功能实现、组件封装及高级扩展(如节点类型定制、连接样式优化等),并提供了性能优化方案以应对大数据量场景。最终,展示了基础网络拓扑、实时更新拓扑等应用实例,为开发者提供了一套完整的实现思路和实践经验。
1711 78
|
缓存 JavaScript 前端开发
Vue 基础语法介绍
Vue 基础语法介绍