Vue组件开发--插槽使用详解

一、概述

在进行Vue组件开发时,当组件内某一部分标签不确定,或者补应该按固定标签来写死模板代码时。

我们可以对不确定的位置,定义一个插槽,等待调用者调用该组件的时候再把内容传入。

这样一来组件就拥有了更强的通用性。该插槽插入什么内容完全取决于父组件如何使用。

二、如何使用插槽

2.1 基本使用

1)使用步骤

  • 组件内使用<slot></slot>占位

  • 使用组件时,在组件标签夹着的地方, 传入标签替换到slot位置上

2)代码示例

子组件:

<template>
  <h2>{
    
    {
    
     title }}</h2>
  <div class="content">
    <slot></slot>
  </div>
</template>

<script>
  export default {
    
    
    props: {
    
    
      title: {
    
    
        type: String,
        default: "title的默认值"
      }
    }
  }
</script>

父组件:

<template>
  <div class="app">
    <!-- 1.内容是button -->
    <show-message title="哈哈哈">
      <button>我是按钮元素</button>
    </show-message>

    <!-- 2.内容是超链接 -->
    <show-message>
      <a href="#">百度一下</a>
    </show-message>

    <!-- 3.内容是一张图片 -->
    <show-message>
      <img src="@/img/kobe02.png" alt="">
    </show-message>

    <!-- 4.内容没有传递 -->
    <show-message></show-message>
  </div>
</template>

<script>
  // 组件引入
  import ShowMessage from './ShowMessage.vue'

  export default {
    
    
    // 组件注册
    components: {
    
    
      ShowMessage
    }
  }
</script>

由于使用了插槽,所以可以传递按钮、超链接、图片等任何DOM元素。组件、普通文本内容都时可以的。

插槽的内容完全取决于父组件使用子组件时传递的元素。

2.2 设置插槽的默认内容

如果父组件没有给插槽传递内容时,我们可以给插槽设置默认内容。

只需要在定义插槽的<solt>标签夹着的位置写上内容,这个内容只会在没有提供插入的内容时,才会显示。

这就是插槽的默认值。

<template>
  <div class="content">
    <slot>
    	插槽的默认值
    </slot>
  </div>
</template>

2.3 具名插槽

如果一个组件中含有多个插槽,那父组件传递的内容会渲染到那一个插槽上面呢?

它会把传递的内容同时渲染到三个插槽上,三个插槽获得的内容完全一样。

为了解决这个问题,我们可以给插槽起一个名字。以此来确定父组件传递的内容属于哪一个插槽。

子组件:

<template>
  <div class="nav-bar">
    <div class="left">
     <!-- name属性可以给插槽取一个名字 -->
      <slot name="left">left</slot>
    </div>
    <div class="center">
      <slot name="center">center</slot>
    </div>
    <div class="right">
      <slot name="right">right</slot>
    </div>
  </div>

  <div class="other">
    <slot name="default"></slot>
  </div>
</template>

<script>
  export default {
    
    

  }
</script>

父组件:

<template>
  <nav-bar>
    <!-- v-solt指令 指定这个template属于哪一个插槽 -->
    <template v-slot:left>
      <button>{
    
    {
    
     leftText }}</button>
    </template>
 	
	<!-- v-solt指令 可以简写为# -->
    <template #center>
      <span>内容</span>
    </template>

    <template v-slot:right>
      <a href="#">登录</a>
    </template>
  </nav-bar>
</template>

<script>
  // 组件引入
  import NavBar from './NavBar.vue'

  export default {
    
    
    // 组件注册
    components: {
    
    
      NavBar
    },
    data() {
    
    
      return {
    
    
        leftText: "返回"
      }
    }
  }
</script>
  • 具名插槽顾名思义就是给插槽起一个名字,只需要在 <solt>标签上添加name属性

    一个不带 name 属性的slot,会有隐含的名字 default

  • 父组件给插槽传递内容时,只需要使用<template>标签和v-solt指令指定这段内容属于那一个插槽即可

  • v-onv-bind 一样,v-slot 也有缩写;v-slot 指令的缩写字符为 #

2.4 动态插槽

不写死v-slot指令的值,而是使用一个变量position去动态指定内容传递给那个插槽。

<template>

  <nav-bar>
    <template v-slot:[position]>
      <a href="#">注册</a>
    </template>
  </nav-bar>
  <button @click=" position = 'left' ">左边</button>
  <button @click=" position = 'center' ">中间</button>
  <button @click=" position = 'right' ">右边</button>
</template>

<script>
  import NavBar from './NavBar.vue'

  export default {
    
    
    components: {
    
    
      NavBar
    },
    data() {
    
    
      return {
    
    
        position: "center"
      }
    }
  }
</script>

2.5 作用域插槽

1)渲染作用域

  • 父级模板里的所有内容都是在父级作用域中编译的

  • 子模板里的所有内容都是在子作用域中编译的

其实就一句话,渲染模板的时候,模板中涉及的变量只能读取本组件内定义的Vue变量。

是无法跨组件读取的。

2)作用域插槽

有时候我们希望插槽可以访问到子组件中的内容,虽然不能直接跨组件访问。

但是Vue提供了作用域插槽的方式,来完成这个需求。

子组件:

<template>
  <div class="tab-control">
    <template v-for="(item, index) in titles" :key="item">
      <div class="tab-control-item"
           :class="{ active: index === currentIndex }"
           @click="itemClick(index)">
        <slot :row="item">
          <span>{
    
    {
    
     item }}</span>
        </slot>
      </div>
    </template>
  </div>
</template>

<script>
  export default {
    
    
    props: {
    
    
      titles: {
    
    
        type: Array,
        default: () => []
      }
    },
    data() {
    
    
      return {
    
    
        currentIndex: 0
      }
    },
    emits: ["tabItemClick"],
    methods: {
    
    
      itemClick(index) {
    
    
        this.currentIndex = index
        this.$emit("tabItemClick", index)
      }
    }
  }
</script>

父组件:

<template>
  <div class="app">
    <!-- 1.tab-control: button -->
    <tab-control :titles="['衣服', '鞋子', '裤子']" 
                 @tab-item-click="tabItemClick">
      <template v-slot:default="props">
        <button>{
    
    {
    
     props.row }}</button>
      </template>
    </tab-control>
  </div>
</template>

<script>
  import TabControl from './TabControl.vue'

  export default {
    
    
    components: {
    
    
      TabControl
    },
    data() {
    
    
      return {
    
    
        pageContents: [ "衣服列表", "鞋子列表", "裤子列表" ],
        currentIndex: 0
      }
    },
    methods: {
    
    
      tabItemClick(index) {
    
    
        console.log("app:", index)
        this.currentIndex = index
      }
    }
  }
</script>

其实核心部分就是这么使用的:

  • 子组件再插槽标签上定义了一个row属性。
<slot :row="item">
	<span>{
    
    {
    
     item }}</span>
</slot>
  • 父组件上使用v-slot指令绑定到没有起名的插槽上,并定义了一个变量props
<template v-slot:default="props">
	<button>{
    
    {
    
     props.row }}</button>
</template>

这个props变量,其实就是把对应的<slot></slot>标签上的属性全部封装成了一个对象。

这里的props就相当于:

{
    
    row:item}

只不过这里的item应该是子组件中的具体值。

这样使用的时候可以自定义目标内容,然后通过props.row来调用。

3)独占默认插槽的简写

  • 如果我们的插槽是默认插槽default,那么在使用的时候 v-slot指令的时候,

    v-slot:default="slotProps"可以简写为v-slot="slotProps"。

  • 如果插槽只有默认插槽时,组件的标签可以被当做插槽的模板来使用

    <tab-control :titles="['衣服', '鞋子', '裤子']" 
                 @tab-item-click="tabItemClick"
                 v-slot="props">
        <button>{
          
          {
          
           props.item }}</button>
    </tab-control>
    

    这个时候也就无需编写<template>标签了。

猜你喜欢

转载自blog.csdn.net/qq_44749491/article/details/127128583