Vue 组件插槽

news/2024/7/10 1:33:53 标签: 前端, Vue

目录

一、组件插槽

1.1、单个插槽

2.2、具名插槽

2.3、作用域插槽

插槽,我要钻到你的怀里

默认插槽

具名插槽

作用域插槽

插槽默认值


一、组件插槽

组件的最大特性就是 复用性 ,而用好插槽能大大提高组件的可复用能力

1.1、单个插槽

当子组件模板只有一个没有属性的插槽时,父组件传入的整个内容片段将插入到插槽所在的 DOM 位置,并 替换 掉插槽标签本身。

2.2、具名插槽

有时我们需要多个插槽,来完成对应的数据自定义显示。

一个不带 name 的 <slot> 出口会带有隐含的名字 “default” 。

自 2.6.0 起有所更新。已废弃的使用 slot

# 子组件
<div class="container">
  <header> 
<slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
</div>

# 父组件
<app-layout>
    // 老写法
    <h1 slot="header">这里可能是一个页面标题</h1>
// 新写法
// v-slot 只能添加在 <template> 上
// 简写 v-slot:header ==  #header
	<template v-slot:header>
    	<h1>这里可能是一个页面标题</h1>
 	</template>

  <p>主要内容的一个段落。</p>
</app-layout>

2.3、作用域插槽

作用域插槽 是一种特殊类型的插槽,用作一个 (能被传递数据的) 可重用模板,来代替已经渲染好的元素。在子组件中,只需将数据传递到插槽,就像你将 prop 传递给组件一样

<div id="app">
    <child :users='users'>
      <!-- 
        vue2.6之前
       -->
      <!-- <h6 slot="action" slot-scope="row" @click="pdel(row)">删除一下</h6> -->
      <!-- 
         vue2.6之后
        -->
      <!-- <template v-slot:action="row">
        <h3 @click="pdel(row)">删除</h3>
      </template> -->
      <template #action="row">
        <h3 @click="pdel(row)">删除</h3>
      </template>
    </child>
  </div>

  <script type="text/template" id="userhtml">
    <div>
      <table width="600" border="1">
        <tr>
          <th>ID</th>
          <th>姓名</th>
          <th>操作</th>
        </tr>
        <tr v-for="(item,index) in users" :key="item.id">
          <td>{{item.id}}</td>
          <td>{{item.name}}</td>
          <td>
            <!-- 通过slot传数据,此slot为作用域插槽 -->
            <slot name="action" :info="item">
              <button @click="del(index)">删除</button>
            </slot>
          </td>
        </tr>
      </table>
    </div>
  </script>
  <script>
    const child = {
      props: ['users'],
      name: 'child',
      template: '#userhtml',
      methods: {
        del(index) {
          console.log(index)
        }
      }
    }

    const vm = new Vue({
      el: '#app',
      data() {
        return {
          users: [
            { id: 1, name: '张三' },
            { id: 2, name: '李四' },
            { id: 3, name: '王五' },
          ]
        }
      },
      components: { child },
      methods: {
        pdel(row) {
          console.log(row.info)
        }
      }

    })
  </script>


插槽,我要钻到你的怀里

插槽,相信每一位 Vue 都有使用过,但是如何更好的去理解插槽,如何去自定义插槽,今天小编为你带来更形象的说明。

默认插槽

大学毕业刚上班,穷鬼一个,想着每个月租房还要掏房租,所以小编决定买一个一居室,东拼西凑借了一堆债,终于凑够了首付,买了一个小小的毛坯房。我们可以把这个一居室的毛坯房想想成一个组件,这个房子的户型,面积,楼层都是固定的,但是室内如何装修,摆什么家具,这个却是由你来决定的,房间内部就可以理解为插槽,允许用户去自定义内容。

1. 开发商终于将一居室开发完交房了

<template>
  <!--这是一个一居室-->
  <div class="one-bedroom">
    <!--添加一个默认插槽,用户可以在外部随意定义这个一居室的内容-->
    <slot></slot>
  </div>
</template>

2. 小编要开始装修了

<template>
  <!--这里一居室-->
  <one-bedroom>
    <!--将家具放到房间里面,组件内部就是上面提供的默认插槽的空间-->
    <span>先放一个小床,反正没有女朋友</span>
    <span>再放一个电脑桌,在家还要加班写bug</span>
  </one-bedroom>
</template>
<script>
import OneBedroom from '../components/one-bedroom'
export default {
  components: {
    OneBedroom
  }
}
</script>

具名插槽

过了几年,小编有了女朋友,准备结婚了,一居室房间肯定不行啊,丈母娘嫌小不同意,没办法,只能又凑钱买大房子,买了一个两居室(穷逼一个),因为是两居室,所以有了主卧和次卧之分,装修是否也不能把主卧和次卧装修的一模一样,所以就需要进行区分。将房子想想成组件,那么组件就有两个插槽,并且需要起名字进行区分。

1. 开发商终于开发完交房了

<template>
  <div class="two-bedroom">
    <!--这是主卧-->
    <div class="master-bedroom">
      <!---主卧使用默认插槽-->
      <slot></slot>
    </div>
    <!--这是次卧-->
    <div class="secondary-bedroom">
      <!--次卧使用具名插槽-->
      <slot name="secondard"></slot>
    </div>
  </div>
</template>

2. 小编要卖血攒钱装修了

<template>
  <two-bedroom>
    <!--主卧使用默认插槽-->
    <div>
      <span>放一个大床,要结婚了,嘿嘿嘿</span>
      <span>放一个衣柜,老婆的衣服太多了</span>
      <span>算了,还是放一个电脑桌吧,还要写bug</span>
    </div>
    <!--次卧,通过v-slot:secondard 可以指定使用哪一个具名插槽, v-slot:secondard 也可以简写为 #secondard-->
    <template v-slot:secondard>
      <div>
        <span>父母要住,放一个硬一点的床,软床对腰不好</span>
        <span>放一个衣柜</span>
      </div>
    </template>
  </two-bedroom>
</template>
<script>
import TwoBedroom from '../components/slot/two-bedroom'
export default {
  components: {
    TwoBedroom
  }
}
</script>

作用域插槽

装修的时候,装修师傅问我洗衣机是要放到卫生间还是阳台,一般情况下开发商会预留放洗衣机的位置。而这个位置可以理解为插槽传的参数,这个就是作用域插槽。

1. 看一下卫生间插槽传了什么参数

<template>
  <div class="two-bedroom">
    <!--其他内容省略-->
    <div class="toilet">
      <!--通过v-bind 可以向外传递参数, 告诉外面卫生间可以放洗衣机-->
      <slot name="toilet" v-bind="{ washer: true }"></slot>
    </div>
  </div>
</template>

2. 把洗衣机放到卫生间

<template>
  <two-bedroom>
    <!--其他省略-->
    <!--卫生间插槽,通过v-slot="scope"可以获取组件内部通过v-bind传的值-->
    <template v-slot:toilet="scope">
      <!--判断是否可以放洗衣机-->
      <span v-if="scope.washer">这里放洗衣机</span>
    </template>
  </two-bedroom>
</template>

插槽默认值

小编的同事不想等期房,所以就买了二手房,二手房前业主都装修好了,可以直接入住。当然也可以重新装修,下面是同事买的二手房。

1. 这是装修好的二手房

<template>
  <div class="second-hand-house">
    <div class="master-bedroom">
      <!--插槽可以指定默认值,如果外部调用组件时没有修改插槽内容,则使用默认插槽-->
      <slot>
        <span>这里有一张水床,玩的够嗨</span>
        <span>还有一个衣柜,有点旧了</span>
      </slot>
    </div>
    <!--这是次卧-->
    <div class="secondary-bedroom">
      <!--次卧使用具名插槽-->
      <slot name="secondard">
        <span>这里有一张婴儿床</span>
      </slot>
    </div>
  </div>
</template>

2. 同事决定先把主卧装修了,以后结婚用

<second-hand-house>
  <!--主卧使用默认插槽,只装修主卧-->
  <div>
    <span>放一个大床,要结婚了,嘿嘿嘿</span>
    <span>放一个衣柜,老婆的衣服太多了</span>
    <span>算了,还是放一个电脑桌吧,还要写bug</span>
  </div>
</second-hand-house>

自己项目中的使用 , 仅供参考 :

比如我这里有很多页面的头部都一样,所以这里我们可以利用插槽的复用性来进行一下代码的简化 :

<template>
  <div>
    <div class="header">
      <img src="../assets/image/LOGO.png">
    </div>
      <!--具名插槽-->
      <slot name="content"></slot>
    </div>
  </div>
</template>

<script>
export default {}
</script>

使用 : 

<template>
  <div id="dwBodyUser">
    <public-header>
      <el-tabs
        v-model="activeName"
        @tab-click="handleClick"
        slot="content"
      >
        <el-tab-pane
          label="所有事项"
          name="first"
          :model="formData"
          ref="formDatas"
        >
          <!-- 所有事项组件 -->
          <all-matters></all-matters>
        </el-tab-pane>
        <el-tab-pane
          label="场景共享"
          name="second"
          :model="formData"
          ref="formDatas"
        >
          <!-- 场景共享组件 -->
          <scene-sharing></scene-sharing>
        </el-tab-pane>
      </el-tabs>
    </public-header>
  </div>
</template>

<script>
import publicHeader from '@/components/publicHeader/index.vue'
import allMatters from './component/allMattersTab.vue'
import screnSharing from './component/sceneSharingTab.vue'

export default {
  components: {
    publicHeader,  // 公共头部组件
    allMatters,    // 所有事项组件
    sceneSharing,  // 场景共享组件
  }
}
</script>

还有一个 公共 Table 示例 :

<!-- 作者 : 小灰狼
     功能 : 所有事项
     时间 : 2022/03 -->
<template>
  <div>
    <el-table
      v-loading="loading"
      :data="tableList"
      style="100%"
      :header-cell-style="{ background: '#EFEFEF', textAlign: 'center' }"
      :border="true"
    >
      <el-table-column
        type="selection"
        width="55"
        align="center"
        v-if="showCheckBox"
      ></el-table-column>
      <el-table-column label="序号" width="120" v-if="showNumber">
        <template slot-scope="scope">
          {{ scope.$index + 1 }}
        </template>
      </el-table-column>
      <el-table-column
        v-for="(item, index) in headerList"
        :key="index"
        :prop="item.props"
        :label="item.label"
        :min-width="item.minWidth"
        align="center"
      ></el-table-column>
      <el-table-column label="操作" min-width="300" align="center">
        <template slot-scope="scope">
          <!-- 事项操作插槽 -->
          <slot name="matterOperation" :row="scope.row"></slot>
          <!-- 场景操作插槽 -->
          <slot name="sceneOperation" :row="scope.row"></slot>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
import { log } from "console";
export default {
  name: "Table",
  props: {
    headerList: {
      type: Array,
    },
    tableList: {
      type: Array,
    },
    showCheckBox: {
      // 是否显示多选框
      type: Boolean,
      default: false,
    },
    showNumber: {
      // 是否显示序号
      type: Boolean,
      default: true,
    },
    content: {
      type: String,
      default: "删除",
    },
    loading: {
      // 是否显示 Loading 加载
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      listItem: "",
    };
  },
  methods: {
    tabRowClick(item) {
      console.log(item, "item");
      this.$emit("tabRowClick", item);
      this.listItem = item;
    },
  },
};
</script>

<style lang="scss" scoped>
.cell button {
  border: none;
  padding-left: 0;
}
</style>

使用 :

<template>
  <div>
    <public-table
      :tableList="tableList"
      :showNumber="formData.showNumber"
      :headerList="headerList"
    >
      <!-- 场景操作插槽 -->
      <template #sceneOperation>
        <el-tooltip content="占位">
          <el-button
            size="small"
            icon="el-icon-edit-outline"
          ></el-button>
        </el-tooltip>
      </template>
    </public-table>
  </div>
</template>

<script>
import publicTable from '@/components/publicTable/index'

export default {
  components: {
    publicTable,  // 公共表格组件
  }
}
</script>

http://www.niftyadmin.cn/n/1498133.html

相关文章

CCF CSP刷题记录25——201809-1卖菜(Java)

试题编号&#xff1a;201809-1试题名称&#xff1a;卖菜时间限制&#xff1a;1.0s内存限制&#xff1a;256.0MB问题描述&#xff1a; 问题描述   在一条街上有n个卖菜的商店&#xff0c;按1至n的顺序排成一排&#xff0c;这些商店都卖一种蔬菜。   第一天&#xff0c;每个商…

项目重温 _ 查漏补缺

目录 动态路由传参 query 方式传参 params 方式传参 组件间传值 Vue 中如何动态的绑定图片 Vue 动态绑定背景图片 Vue 中 v-on 如何绑定多个事件 &#xff1f; 将块元素旋转 90 vue-router 如何判断是从哪个路径跳转过来的 &#xff1f; 处理后端返回的列表数据 导…

HDU 2053 Switch Game(开灯问题,完全平方数)

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid2053 题目大意&#xff1a;灯开始是关着的&#xff0c;有n盏灯&#xff0c;i从1数到n每当灯的序号是i的倍数的时候就对灯进行一次操作&#xff08;开->关&#xff0c;关->开&#xff09;&#xff0c;求最…

springboot jpa sql打印_SpringBoot 整合 Spring Data JPA

首先我们先了解一下 SpringBoot和 SpringData JPA是什么?SpringBoot是一个框架,一种全新的编程规范,它的产生简化了框架的使用所谓简化是指简化了Spring众多框架中所需的大量繁琐的配置文件所以SpringBoot是一个服务于框架的框架,服务范围是 : 简化配置文件SpringData : Sprin…

CCF CSP刷题记录26——201809-2买菜(Java)

试题编号&#xff1a;201809-2试题名称&#xff1a;买菜时间限制&#xff1a;1.0s内存限制&#xff1a;256.0MB问题描述&#xff1a; 问题描述   小H和小W来到了一条街上&#xff0c;两人分开买菜&#xff0c;他们买菜的过程可以描述为&#xff0c;去店里买一些菜然后去旁边的…

CCF CSP刷题记录27——201812-1小明上学(Java)

试题编号&#xff1a;201812-1试题名称&#xff1a;小明上学时间限制&#xff1a;1.0s内存限制&#xff1a;512.0MB问题描述&#xff1a; 题目背景   小明是汉东省政法大学附属中学的一名学生&#xff0c;他每天都要骑自行车往返于家和学校。为了能尽可能充足地睡眠&#xff…

asp.mvc 4项目发布文件目录结构_如何用SpringBoot(2.3.3版本)快速搭建一个项目?文末有小彩蛋...

(一)概述SpringBoot作为现在工作中最常用的一个框架&#xff0c;大部分人对他都只做到了会用这一步&#xff0c;但是SpringBoot的许多细节却被我们所忽略掉了&#xff0c;因此我打算写这样一个有关SpringBoot的系列文章&#xff0c;争取能让不管是新手还是老手都能从中再学到东…

SDUT _2117 数据结构实验之链表二:逆序建立链表

点击打开链接 数据结构实验之链表二&#xff1a;逆序建立链表 Time Limit: 1000MS Memory Limit: 65536KBSubmit Statistic DiscussProblem Description 输入整数个数N&#xff0c;再输入N个整数&#xff0c;按照这些整数输入的相反顺序建立单链表&#xff0c;并依次遍历输出单…