el-table 递归表头slot透传封装

文章详细描述了如何在Vue中使用Table组件和Column组件进行列头的深度slot封装,包括递归结构和性能考量,以及如何通过`deepSlotNames`传递数据。作者还提示了关于性能影响的讨论点。
摘要由CSDN通过智能技术生成

 最终效果

实现过程

组件封装

Table.vue组件

<template>
  <el-table :data="list">
    <Column v-for="column in columns" :key="column.prop" :column="column" :sortParams="sortParams" @sortChange="handleSortChange">
      <template v-if="column.slotName" #[column.slotName]>
        <slot :name="column.slotName"></slot>
      </template>
      <template v-for="item in column.deepSlotNames" #[item]="scope">
        <slot  :name="item" v-bind="scope"></slot>
      </template>
      
    </Column>
  </el-table>
</template>

<script lang="ts">
import Column from './Column.vue';

export default {
  props: {
    columns: {
      type: Array,
      default: () => [
        { prop: 'name', label: '姓名', sortable: true },
        { prop: 'age', label: '年龄', sortable: true },
        { prop: 'info', label: '个人信息', deepSlotNames: ['father', 'mother', 'brother', 'xiaox'], children: [
          { prop: 'parent', label: '父母', deepSlotNames: ['father', 'mother'], children: [
            { prop: 'father', label: '父亲', slotName: 'father'  },
            { prop: 'mother',label: '母亲', slotName: 'mother', children: [
            ]  }
          ]},
          { prop: 'brother', label: '兄弟', slotName: 'brother' },
          { prop: 'school', label: '学校', deepSlotNames: ['xiaox'], children: [
            { prop: 'yiwu', label: '义务教育阶段', deepSlotNames: ['xiaox'], children: [
              { prop: 'xiaox', label: '小学', slotName: 'xiaox' }
            ] }
          ] }
          ] 
        },
        { prop: 'operation', label: '操作', slotName: 'operation' }
      ]
    }
  },
  components: {
    Column,
  },
  data() {
    return {
    
      list: [
        { id: 1, name: '小明', age: 12, father: '小明爸爸1', mother: '小明妈妈' },
        { id: 2, name: '小红', age: 22, father: '小红爸爸2', mother: '小红妈妈' },
        { id: 3, name: '小白', age: 32, father: '小白爸爸3', mother: '小白妈妈' },
      ],
      sortParams: {}
    }
  },

  methods: {
    handleSortChange() {
      console.log('sss22', this.sortParams)
    }
    
  }
}
</script>

Column 表头组件

<template>
  <el-table-column :label="column.label" :prop="column.prop">
    <Column v-for="columnItem in column.children" :column="columnItem" :key="columnItem.prop">
      <template v-for="item in column.deepSlotNames" #[item]="scope">
        <slot :name="item" v-bind="scope"></slot>
      </template>

      <template #[column.slotName]="scope">
        <slot :name="column.slotName" v-bind="scope"></slot>
      </template>

    </Column>
    <template v-if="column.sortable" #header>
      <div class="cust-header">
        <span>{{ column.label }}</span>
        <SortItem :sort.sync="sortParams[column.prop]" @sortChange="handleSortChange"></SortItem>
      </div>
    </template>
    <!-- 递归出口 -->
    <template v-if="column.slotName" #default="scope">
      <slot :name="column.slotName" v-bind="scope"></slot>
    </template>

  </el-table-column>
</template>

<script lang="ts">
import { PropType } from 'vue'
import SortItem from './SortItem.vue'

type TColumn = {
  label: string
  prop: string
  deepSlotNames?: string[]
  children?: TColumn
  [key: string]: any
}
export default {
  name: 'Column',
  components: {
    SortItem
  },
  props: {
    column: {
      type: Object as PropType<TColumn>,
      default: () => ({})
    },
    sortParams: {
      type: Object,
      default: () => ({})
    }
  },
  methods: {
    handleSortChange() {
      this.$emit('sortChange')
    }
  }
}
</script>

<style lang="css">
.cust-header {
  display: flex;
  justify-content: space-between;
}
</style>

SortItem组件

<template>
  <div class="table-sort">
    <div class="table-sort-up" @click="handleSortMode('up')" :class="{
      active: sort === 'asc'
    }">^</div>
    <div class="table-sort-down"  @click="handleSortMode('down')" :class="{
      active: sort === 'desc'
    }">v</div>
  </div>
</template>

<script lang="ts">
import { PropType } from 'vue'

export default {
  props: {
    sort: {
      type: String as PropType<'asc' | 'desc'>
    }
  },

  methods: {
    handleSortMode(type: string) {
      if (type === 'up') {
        const newValue = this.sort === 'asc' ? '' : 'asc'
        this.$emit('update:sort', newValue)
      } else {
        const newValue = this.sort === 'desc' ? '' : 'desc'
        this.$emit('update:sort', newValue)
      }
      this.$emit('sortChange')
    }
  }
}
</script>

<style lang="css">
.table-sort {
  display: flex;
  flex-direction: column;
}
.table-sort-up, .table-sort-down {
  width: 16px;
  height: 16px;
  text-align: center;
  line-height: 16px;
  cursor: pointer;
}
.table-sort-up.active, .table-sort-down.active {
  color: red;
}
.table-sort-up  {
  font-size: 16px;
}
.table-sort-down {
  font-size: 14px;
}
</style>

封装表格调用slot透传

<Table>
      <template #operation>操作-slot</template>
      <template #brother>brother</template>
      <template #father="{ row }">
        <div @click="handleGetRow(row)">{{ row.id }}: father-slot</div>
      </template>
      <template #mother="{ row }">{{ row.id }}: mother-slot</template>
      <template #xiaox>xiaox-slot</template>
    </Table>

特殊说明,由于递归层级不确定,slot透传主要靠 deepSlotNames 这个字段接收slot并传递下去,还不确定性能影响,如果有更好的方式欢迎留言讨论

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值