Vue进阶(三)插槽slot,并使用slot开发高级分页组件

如果对组件不太了解,可以先阅读笔者的这两篇文章,在对组件有了一定的了解之后,在查看本篇文章:
vue进阶(一),深入了解组件,自定义组件
Vue进阶(二)设计高级组件——自定义通知

注意:本篇文章的重点是使用slot开发一个分页组件,如果希望详细了解Vue中slot的用法,可以查看官网文档,同时,如果您在阅读本文中发现错误或者使用不当的地方,还请您指出修正!

1. 什么是插槽

Vue实现了一套内容分发的API,而<slot>元素就是承载分发内容的出口。
使用<slot>,我们可以这样写一个组件:
slotTest.vue

  <div>
    <span>这个组件中使用了slot元素</span>
    <slot></slot>
  </div>

使用slotTest.vue:

    <current-name>
      这个内容将展示在slot的位置
    </current-name>

显示效果:
在这里插入图片描述
当组件在渲染时,<slot></slot>将会被替换为“这个内容将展示在slot的位置”。插槽内可以包含任何模板代码,包括 HTML,甚至其他自定义组件:

    <current-name>
      <div>这个内容将展示在slot的位置</div>
    </current-name>

显示结果:
在这里插入图片描述
如果slotTesttemplate中没有包含一个<slot>元素,那么,在使用slotTest是,<slot>任意内容</slot>组件起始标签和结束标签之间的任何内容都会被抛弃。

2. 插槽的具体使用

现在有这样的一个组件,其可以显示一些个人信息。
person.vue:

<template>
  <div>
    <span>这个组件中使用了slot元素</span>
    <div>
      firstName:
      <slot name="firstName"></slot>
    </div>
    <div>
      lastName:
      <slot name="lastName" :last_name="lastname"></slot>
    </div>
    <div>
      sex:
      <slot name="sex">(如果没有使用到这个插槽,那么这就是这个插槽的默认填充)</slot>
    </div>
   <div>
      身高:
      <slot name="height">如果使用了这个插槽,那么这里的内容就无效了</slot>
    </div>
    <div>
      体重:
      <slot name="weight"></slot>
    </div>
    <slot/>
  </div>
</template>

<script>
export default {
   
  name: "currentName",
  data(){
   
    return{
   
      firstName: 'Niall',
      lastname: 'August'
    }
  }
}
</script>

使用person.vue:

<template>
  <div>
    <person>
      <template v-slot:height>180cm</template>
      <template v-slot:[slotName]>{
   {
   firstname}}</template>
      <template v-slot:lastName=last>{
   {
   last.last_name}}</template>
      <template #weight>90kg</template>
      <template><div>这个内容将展示在default slot的位置</div></template>
    </person>
  </div>
</template>

<script>
import person from "./components/person";
export default {
   
  name: "Test",
  components: {
   
    person
  },
  data(){
   
    return{
   
      slotName:'firstName',
      firstname: 'Jack'
    }
  }
}
</script>

显示结果:
在这里插入图片描述

2.1 具名插槽

person.vue中,我们设置了多个插槽,为了能够区分不同的插槽,我们为设置了每个插槽的name属性,一个不带name的slot出口都会带有一个默认名字default
当我们在使用组件时,在分发内容上就需要在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称,以上面我们分发height时:

	<template v-slot:height>180cm</template>

这里我们还需要注意,我们根据slot.name来分发内容,但是和我们在使用组件时的顺序没有关系,也就是说,我们分发内容的顺序和显示没有关系,显示的顺序由我们的组件中slot的顺序决定。所以,虽然我们在使用person时将<template v-slot:height>180cm</template>写在了最前面,但是最终的显示内容还是按照了person中slot的顺序来显示的。
在设置了slot.name之后,<template> 元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容。
也就是上文中的:

<template><div>这个内容将展示在default s
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要写一个高级的通用的crud组件,可以遵循以下步骤: 1. 定义props - columns: 列定义,包括列名称、字段、是否可编辑等信息 - data: 数据源,需要是一个数组 - editable: 是否可编辑,控制表格是否可编辑 - rowKey: 行key,用于区分每一行数据的唯一标识 - showPagination: 是否显示分页器 - pageSizes: 分页器可选的每一页条数 - pageSize: 每一页的条数 - currentPage: 当前页码 2. 定义data - tableData: 表格数据源,需要在mounted中初始化,可以使用props中的data - currentPage: 当前页码,需要在mounted中初始化,可以使用props中的currentPage - total: 数据总数,需要在mounted中初始化,可以使用props中的data的长度 - pageSize: 每一页的条数,需要在mounted中初始化,可以使用props中的pageSize 3. 定义computed - displayedData: 显示的数据,根据当前页码和每一页的条数计算得出 - displayedColumns: 显示的列,根据传入的columns和editable计算得出 4. 定义methods - handleSizeChange: 分页器每一页条数改变时的回调函数,需要更新pageSize和total - handleCurrentChange: 分页器当前页码改变时的回调函数,需要更新currentPage - handleEdit: 表格中的编辑操作的回调函数,需要更新tableData中的对应数据 - handleDelete: 表格中的删除操作的回调函数,需要从tableData中删除对应数据 5. 定义template - 使用el-table组件展示数据源 - 使用v-if控制是否显示分页器 - 使用v-for循环展示列定义中的列 - 使用v-if控制列是否可编辑 - 使用slot插槽自定义每一行的操作列 完整的代码如下: ```vue <template> <div> <el-table :data="displayedData" :columns="displayedColumns"> <template #default="{row}"> <td> <slot name="operation" :row="row"></slot> </td> </template> </el-table> <el-pagination v-if="showPagination" :page-sizes="pageSizes" :page-size="pageSize" :current-page.sync="currentPage" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> </template> <script> export default { name: 'CrudTable', props: { columns: { type: Array, default: () => [] }, data: { type: Array, default: () => [] }, editable: { type: Boolean, default: false }, rowKey: { type: String, default: 'id' }, showPagination: { type: Boolean, default: true }, pageSizes: { type: Array, default: () => [10, 20, 30, 40, 50] }, pageSize: { type: Number, default: 10 }, currentPage: { type: Number, default: 1 } }, data() { return { tableData: [], currentPage: 1, total: 0, pageSize: 10 } }, computed: { displayedData() { const start = (this.currentPage - 1) * this.pageSize const end = start + this.pageSize return this.tableData.slice(start, end) }, displayedColumns() { return this.columns.map(column => { const newColumn = { ...column } if (this.editable && column.editable) { newColumn.editable = true newColumn.scopedSlots = { default: scope => { return ( <el-input v-model={scope.row[column.prop]} size="mini" clearable /> ) } } } return newColumn }) } }, methods: { handleSizeChange(pageSize) { this.pageSize = pageSize this.total = this.tableData.length }, handleCurrentChange(currentPage) { this.currentPage = currentPage }, handleEdit(row) { const index = this.tableData.findIndex(item => item[this.rowKey] === row[this.rowKey]) if (index > -1) { this.tableData.splice(index, 1, row) } }, handleDelete(row) { const index = this.tableData.findIndex(item => item[this.rowKey] === row[this.rowKey]) if (index > -1) { this.tableData.splice(index, 1) } } }, mounted() { this.tableData = this.data this.currentPage = this.currentPage this.total = this.tableData.length this.pageSize = this.pageSize } } </script> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值