全新的table组件,vue3+element Plus

全新的table组件,vue3+element Plus

全新的table组件,vue3+element Plus

tableList.vue文件

javascript 复制代码
<template>
  <el-table
    ref="tableComRef"
    :data="tableData"
    :stripe="stripe"
    style="width: 100%; height: 100%"
    @sort-change="handleSortChange"
    @selection-change="handleSelectionChange"
    @cell-click="handleCellClick"
    @cell-dblclick="handleCellDblClick"
  >
    <!-- 使用计算属性简化模板逻辑 -->
    <el-table-column
      v-if="hasSelectionColumn"
      type="selection"
      width="50">
    </el-table-column>
    <el-table-column
      v-for="(item, index) in displayColumns"
      :key="item?.property || item?.prop || index"
      :index="indexMethod"
      :width="item?.width"
      align="center"
      :property="item?.property || item?.prop"
      :type="item?.type"
      :label="item?.label || item?.name"
      :sortable="item?.sortable"
      :show-overflow-tooltip="true"
      :fixed="item?.fixed"
    >
      <template #default="scope">
        <!-- 添加具名插槽支持 -->
        <slot :name="item?.property || item?.prop" :row="scope.row" :index="scope.$index" :column="scope.column">
          <div v-if="item?.render" class="center h-[100%]" v-html="item?.render(scope.row)"></div>
          <!-- 添加对自定义事件的支持 -->
          <div v-else-if="item?.renderWithEvent" class="center h-[100%]">
            <component
              :is="item?.renderWithEvent?.component || 'div'"
              v-bind="item?.renderWithEvent?.props ? item?.renderWithEvent?.props(scope.row) : {}"
              @[item?.renderWithEvent?.eventType]="item?.renderWithEvent?.handler ? item?.renderWithEvent?.handler(scope.row) : null"
            >
              {{ item?.renderWithEvent.text ? item?.renderWithEvent?.text(scope.row) : '' }}
            </component>
          </div>
          <!-- 默认显示 -->
          <div v-else>
            {{ scope.row[item?.property || item?.prop] }}
          </div>
        </slot>
      </template>
 
      <!-- 操作栏 -->
      <template v-if="item?.custom" #default="scope">
        <div class="operationAll center cursor-pointer">
          <!-- 每一列操作项需要根据数据的某些字段展示不同项 -->
          <div class="center flex-1 cursor-pointer">
            <slot name="operation" :row="scope.row" :index="scope.$index"></slot>
          </div>
        </div>
      </template>
    </el-table-column>
  </el-table>
</template>
 
<script setup>
import { ref, computed } from 'vue';
const props = defineProps({
  tableHeaderList: {
    type: Array,
    default: () => [],
  },
  tableData: {
    type: Array,
    default: () => [],
  },
  showTooltip: {
    type: Boolean,
    default: false,
  },
  pages: {
    type: Object,
    default: {
      pageSize: 10,
      currentPage: 1,
    },
  },
  stripe: {
    type: Boolean,
    default: false,
  },
});
 
const tableComRef = ref();
const page = computed(() => props.pages);
 
// 计算属性简化模板逻辑
const hasSelectionColumn = computed(() => {
  return props.tableHeaderList.length > 0 && props.tableHeaderList[0]?.type === 'selection';
});
 
const displayColumns = computed(() => {
  if (hasSelectionColumn.value) {
    return props.tableHeaderList.slice(1);
  }
  return props.tableHeaderList;
});
 
const emits = defineEmits();
 
// 排序切换方法,在对应列上点击排序时触发
const handleSortChange = (column, prop, order) => {
  emits('tableSortChange', column, prop, order);
};
 
// 列数据勾选时触发
const handleSelectionChange = (selection) => {
  emits('tableSelectionChange', selection);
};
 
let timer = null;
 
const clickCount = ref(0);
// 当某个单元格被点击时会触发该事件
const handleCellClick = (row, column, cell, event) => {
  clickCount.value++;
  event.stopPropagation(); // 阻止事件冒泡
  timer = setTimeout(() => {
    if (clickCount.value === 1) {
      clearTimeout(timer);
      if (!column.property || column.property === '') return;   // 点击的是操作按钮时不做额外处理
      emits('tableCellClick', row, column, cell, event);
    } else {
      if (!column.property || column.property === '') return;   // 点击的是操作按钮时不做额外处理
      emits('tableCellDblClick', row, column, cell, event);
    }
    clickCount.value = 0;
  }, 500);
};
 
// 当某个单元格被双击时会触发该事件
const handleCellDblClick = (row, column, cell, event) => {
  clearTimeout(timer);
  if (!column.property || column.property === '') return;   // 点击的是操作按钮时不做额外处理
  emits('tableCellDbClick', row, column, cell, event);
};
 
// 初始化tableindex
const indexMethod = (index) => {
  return page.value.pageSize * (page.value.currentPage - 1) + (index + 1);
};
 
defineExpose({
  tableComRef,
});
</script>
 
<style scoped>
:deep(.el-scrollbar__view) {
  height: 100%;
}
:deep(td.el-table__cell) {
  border: 1px solid #f0f0f0;
}
:deep(tr th) {
  border-bottom: 1px solid #f0f0f0;
  border-right: 1px solid #f0f0f0;
}
:deep(.el-table__cell) {
  border-right: 1px solid #f0f0f0;
  z-index: inherit;
}
:deep(th) {
  height: 50px;
  color: #2b3a5a;
  background-color: #ebf3ff;
  border: 1px solid #f0f0f0;
}
</style>

使用方式

template部分

javascript 复制代码
<tableList
    :tableHeaderList="tableHeaderList"
    :data="tableData"
    @table-cell-click="handleTableCellClick"
>
    <template #secondDistributionScene="{ row, index }">
        <el-image style="width: 100px; height: 100px" :src="url" :zoom-rate="1.2" :max-scale="7" :min-scale="0.2"
          :preview-src-list="srcList" show-progress :initial-index="0" fit="cover"/>
      </template>
    <template #operation="{ row, index }">
        <p
            style="color: rgb(57, 150, 252)"
            class="pointer"
            @click="toDetails(row, index)"
        >
            详情
        </p>
    </template>
</tableList>

js部分

javascript 复制代码
// 表头
const tableHeaderList = ref([
    {
        label: '短剧基础信息',
        prop: 'playletName',
        align: 'center',
        render: (val) => {
            const html = `<div class="startX pointer" style="width: 100%;">
                <img src=${val.coverImage || defaultImage} style="display:block;width:30px;height:30px;" @click="handleClick(val)" />
                <p style="margin-left: 10px;width:70%;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;">${val.playletName}</p>
                </div>`;
            return html;
        },
       renderWithEvent: {
            component: 'div',
            text: (row) => row.id,
            eventType: 'click',
            handler: (row) => showDom(row.id)
        }
    },
    {
        label: '观看',
        prop: 'totalViews',
        align: 'center',
    },
    {
        label: '收藏',
        prop: 'totalCollects',
        align: 'center',
        sortable: true,
    },
    {
        label: '分享',
        prop: 'totalShares',
        align: 'center',
        sortable: true,
    },
    {
        label: '付费剧集解锁人数',
        prop: 'totalPayers',
        align: 'center',
        sortable: true,
    },
    {
        label: '分账收益',
        prop: 'copyrightIncome',
        align: 'center',
        sortable: true,
    },
    {
        label: '分销人数',
        prop: 'totalDistributors',
        align: 'center',
        sortable: true,
    },
    {
        label: '操作',
        prop: '',
        align: 'center',
        custom: true,
    },
]);

示例效果

相关推荐
奇迹_h12 小时前
打造你的HTML5打地鼠游戏:零基础入门实践
前端
SuperEugene12 小时前
Vue生态精选篇:Element Plus 的“企业后台常用组件”用法扫盲
前端·vue.js·面试
Neptune112 小时前
JavaScript回归基本功之---类型判断--typeof篇
前端·javascript·面试
贾铭12 小时前
如何实现一个网页版的剪映(三)使用fabric.js绘制时间轴
前端·后端
进击的尘埃12 小时前
微前端沙箱隔离:qiankun 和 wujie 到底在争什么
javascript
子兮曰13 小时前
后端字段又改了?我撸了一个 BFF 数据适配器,从此再也不怕接口“屎山”!
前端·javascript·架构
万少15 小时前
使用Trae轻松安装openclaw的教程-附带免费token
前端·openai·ai编程
颜酱15 小时前
一步步实现字符串计算器:从「转整数」到「带括号与优化」
javascript·后端·算法
浪浪山_大橙子15 小时前
OpenClaw 十分钟快速,安装与接入完全指南 - 推荐使用trae 官方 skills 安装
前端·人工智能
忆江南15 小时前
iOS 可视化埋点与无痕埋点详解
前端