【Vue】vue2.6插槽slot使用详解(更新v-slot用法总结)

在 2.6.0 中,具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot指令)。
它取代了slot slot-scope 这两个目前已被废弃但未被移除且仍在文档中的 attribute

一、 插槽简介

Vue 实现了一套内容分发的 API,即:将<slot></slot>元素作为承载分发内容的出口。

插槽作用: 父页面在组件标签内插入任意内容,子组件内插槽slot控制摆放位置(匿名插槽,具名插槽)。
插槽分类(共三类):

  1. 匿名插槽(也叫默认插槽): 没有命名,有且只有一个
  2. 具名插槽: 相对匿名插槽组件slot标签带name命名的
  3. 作用域插槽: 子组件内数据可以被父页面拿到(解决了数据只能从父页面传递给子组件的问题)

二、插槽的使用

2.1 匿名插槽

规则:

  • 匿名插槽只有一个
  • 一个不带 name<slot> 出口会带有隐含的名字default
  • 父组件调用带有插槽的子组件,并传入值给子组件,替代子组件的默认值
<slot>默认值</slot>

2.2 具名插槽

规则:

  • slotname属性,可以有多个具名插槽
  • 任何没有被包裹在带有v-slot 中的内容都会被视为默认插槽的内容

2.3 匿名与具名插槽的使用

注意 v-slot 只能添加在<template>上 (只有一种例外情况),这一点和已经废弃的 attribute 不同。

定义插槽 base-layout.vue

有时我们需要多个插槽。例如对于一个带有如下模板的 <base-layout> 组件:

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

使用插槽:
在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以v-slot的参数的形式提供其名称:

<base-layout>
  <template v-slot:header>
    <h1>我是头部header</h1>
  </template>

  <p>未指定的内容默认归结为匿名插槽内容1</p>
  未指定的内容默认归结为匿名插槽内容2

  <template v-slot:footer>
    <p>我是尾部footer</p>
  </template>
</base-layout>
//v-slot:default写上感觉和具名写法比较统一,容易理解,也可以不用写

现在<template>元素中的所有内容都将会被传入相应的插槽。
任何没有被包裹在带有 v-slot<template> 中的内容都会被视为默认插槽的内容。

最后页面显示如下

我是头部header
未指定的内容默认归结为匿名插槽内容1
未指定的内容默认归结为匿名插槽内容2
我是尾部footer

2.4. 作用域插槽

自 2.6.0 起有所更新。已废弃的使用 slot-scope attribute 的语法在这里

规则

  • 父级模板里的所有内容都是在父级作用域中编译的;
  • 子模板里的所有内容都是在子作用域中编译的。
  • 作用域插槽让插槽内容能够访问子组件中才有的数据

子组件

 <slot name="todo" :user="user" :test="test">
    {{ user.lastName }}
 </slot> 
 
data() {
    return {
      user:{
        lastName:"张",
        firstName:"三"
      },
      test:[1,2,3,4]
    }
  },
// {{ user.lastName }}是默认数据  v-slot:todo 当父页面没有(="slotProps")时显示: 张

父页面
重点是slotProps接取子组件里:user="user" :test="test"类似属性的数据

<todo-list>
 <template v-slot:todo="slotProps" >
   {{slotProps.user.firstName}}
 </template> 
</todo-list> 
//slotProps 可以随意命名
//slotProps 接取的是子组件标签slot上属性数据的集合所有v-bind:user="user"

最后显示

2.4.1 解构插槽Prop

这样可以使模板更简洁,尤其是在该插槽提供了多个 prop 的时候。

父组件:

// 相当于
function (slotProps) {
 // 插槽内容
}
(slotProps)=>参数可以用slot标签上现有的值({user,test})替换
<todo-list>
 <template v-slot:todo="{user,test}" >
   {{user.firstName}}  //此处原来需要写为{{slotProps.user.firstName}}
 </template> 
</todo-list> 
## 显示 ##
## // yue

子组件:

<slot name="todo" :user="user" :test="test">
    {{ user.lastName }}
</slot> 
data() {
    return {
      user:{
        lastName:"Zhang",
        firstName:"yue"
      },
      test:[1,2,3,4]
    }
  },
 
## 显示 ##
// yue

参数值替换名字

<todo-list>
 <template v-slot:todo="{user:person,test}" >
   {{person.firstName}}
 </template> 
</todo-list> 
 
// v-slot:[dynamicSlotName]="{user:person,test}
## 显示 ##
## // yue

注意v-slot只能添加在<template>上,只有一种例外情况,如下:独占默认插槽(当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用)

2.4.2 独占默认插槽

当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用

父组件:

//原本是需要写template
<todo-list>
 <template v-slot:default="slotProps" >
   {{slotProps.user.firstName}}
 </template> 
</todo-list> 

<!--当被提供的内容只有默认插槽时 v-slot等属性可以直接写在组件标签上-->

<todo-list v-slot:default="slotProps" >
   {{slotProps.user.firstName}}
</todo-list> 

//或者简写
<todo-list #default="slotProps">
   {{slotProps.user.firstName}}
</todo-list> 

子组件:

<slot :user="user" :test="test">
    {{ user.lastName }}
 </slot> 
data() {
    return {
      user:{
        lastName:"Zhang",
        firstName:"yue"
      },
      test:[1,2,3,4]
    }
  },
## 显示 ##
// yue

2.5 缩写形式

v-onv-bind一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #
例如: v-slot:header 可以被重写为#header

使用插槽 <base-layout> 组件:

<base-layout>
  <template #header>
    <h1>我是头部header</h1>
  </template>

  <p>未指定的内容默认归结为匿名插槽内容1</p>
  未指定的内容默认归结为匿名插槽内容2

  <template #footer>
    <p>我是尾部footer</p>
  </template>
</base-layout>

三、插槽示例

3.1 todo-list实例

父页面

<template>
  <div>
    新插槽 v-slot 代替具名插槽 作用于插槽
    <todo-list> 
	    <template #todo="{todos:list}">
	      <div @click = type(todos.id)>
	         {{list.text}}
	      </div>
	    </template>
    </todo-list>  
  </div >
</template>
<script>
import todoList from "@/components/component/slotTodoChildren";
export default {
 name:"vSlot",
 components:{
  todoList
 },
 data() {
   return {

   }
 },
 methods: {
   type(data){
    console.log(data)
   }
 },
}
</script> 

子组件

<template>
  <ul class="slotTodoChildren">
    <li class="list"
      v-for="todo in todoList"
      v-bind:key="todo.id"
    >
      <!--
      我们为每个 todo 准备了一个插槽,
      将 `todo(todoList里的)` 对象作为一个插槽的 prop 传入。
      -->
      <slot name="todo" :todos="todo">
      <!-- 后备内容 -->
      {{ todo.text }}
      </slot>
    </li>
  </ul>
</template>
<script>
export default {
  name:"slotChildren",

  data() {
    return {
      todoList:[
      {
        id:1,      
        text:"扫地"
      },
      {
        id:2,
        text:"做饭"
      },
      {
        id:3,
        text:"擦桌子"
      }
    ]
    }
  },
  created(){
    console.log(this.filteredTodos)
  }
}
</script>
<style scoped>
.slotTodoChildren .list{
  display: block;
  background: #434534;
  line-height:40px;
  margin-top: 10px;
  color: #fff;
  font-size: 24px;
  height: 40px;
}
</style>

3.2 实际使用示例

在这里插入图片描述
title是插槽名,插入的内容是node

老写法

<app-tree
      class="border-spe-right"
      :treeConfig="treeConfig"
      :expandedKeys.sync="treeConfig.defaultExpandedKeys"
      :selectedKeys="treeConfig.defaultSelectedKeys"
      :tree-data="treeData"
      :handle="handle"
      style="width: 20%"
      :onSearch="onSearch"
      :onSelect="onSelect"
      :onLoadData="onLoadData"
      @selectNode="onSelectNode"
    >
      <div slot="title" class="system-role-title" slot-scope="{ node }">
        <div class="title-icon" :class="node.icon"></div>
        <div class="title-label">{{ node.label }}</div>
      </div>
    </app-tree>

新写法

<app-tree
      class="half"
      :treeConfig="treeConfig"
      :expandedKeys.sync="treeConfig.defaultExpandedKeys"
      :selectedKeys="treeConfig.defaultSelectedKeys"
      :checkedKeys.sync="treeConfig.defaultCheckedKeys"
      :tree-data="treeData"
      :onSearch="onSearch"
      :onSelect="onSelect"
      :onLoadData="onLoadData"
    >
      <template #title="{ node }">
        <div class="title-icon" :class="node.icon"></div>
        <div class="title-label">{{ node.label }}</div>
      </template>
    </app-tree>

四、总结

在用上v-slot之后 只需要考虑好

  1. 是否需要命名(匿名插槽,具名插槽)
  2. 父页面是否需要取存在子页面的数据(作用域插槽)
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Vue中,插槽slot)是一种用于组件之间内容分发的机制。它允许父组件向子组件传递内容,使得子组件可以根据需要展示不同的内容。插槽可以用于传递任意类型的内容,包括HTML、文本和其他组件。 Vue中的插槽有三种使用方式:slotslot-scope和v-slot。 1. slotslot标签是最基本的插槽使用方式。父组件可以在子组件的slot标签中放置内容,这些内容将会替换子组件中具名插槽的位置。例如: ```html <!-- 父组件 --> <template> <child-component> <template v-slot:header> <h1>这是标题</h1> </template> </child-component> </template> <!-- 子组件 --> <template> <div> <slot name="header"></slot> <!-- 其他子组件内容 --> </div> </template> ``` 上述代码中,父组件在子组件的插槽中放置了一个标题,子组件通过`<slot name="header"></slot>`来展示这个插槽的内容。 2. slot-scope:slot-scope指令用于在插槽中接收父组件传递的数据。通过这种方式,子组件可以访问父组件的数据,并在插槽中进行处理。例如: ```html <!-- 父组件 --> <template> <child-component> <template v-slot:default="slotProps"> <h1>{{ slotProps.title }}</h1> <p>{{ slotProps.content }}</p> </template> </child-component> </template> <!-- 子组件 --> <template> <div> <slot :title="title" :content="content"></slot> <!-- 其他子组件内容 --> </div> </template> <script> export default { data() { return { title: '这是标题', content: '这是内容' }; } }; </script> ``` 在上述代码中,父组件通过`v-slot:default="slotProps"`将数据传递给子组件的插槽,并在插槽使用`slotProps`来访问这些数据。 3. v-slot:v-slot指令是Vue2.6版本及以上引入的新特性,用于简化插槽语法。它可以直接在子组件上使用,而不需要使用template标签。例如: ```html <!-- 父组件 --> <template> <child-component> <template #header> <h1>这是标题</h1> </template> </child-component> </template> <!-- 子组件 --> <template> <div> <slot name="header"></slot> <!-- 其他子组件内容 --> </div> </template> ``` 在上述代码中,父组件使用`#header`来定义插槽,并在子组件中使用`<slot name="header"></slot>`来展示插槽的内容。 总结一下,slot用于定义插槽的位置,slot-scope用于接收父组件传递的数据,并在插槽中进行处理,v-slot是对插槽语法的简化。这些插槽使用方式可以根据具体需求选择适合的方式。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卸载引擎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值