全新的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,
    },
]);

示例效果

相关推荐
硬汉嵌入式2 小时前
QEMU & FFmpeg作者Fabrice Bellard推出MicroQuickJS,一款面向嵌入式系统JavaScript引擎,仅需10K RAM
javascript·ffmpeg·microquickjs
GitCode官方3 小时前
DevUI 组织 2025 年度运营报告:扎根 AtomGit,开源前端再启新程
前端·开源·atomgit
恋猫de小郭10 小时前
Flutter 正在计划提供 Packaged AI Assets 的支持,让你的包/插件可以更好被 AI 理解和选择
android·前端·flutter
小小前端--可笑可笑10 小时前
Vue / React 单页应用刷新 /login 无法访问问题分析
运维·前端·javascript·vue.js·nginx·react.js
小林敲代码778810 小时前
记一次 Vue 项目首屏优化:从 7.1s 到 0.9s,深挖 Gzip 的力量
前端·javascript·vue.js
前端大卫10 小时前
写给年轻程序员的几点小建议
前端
Highcharts.js11 小时前
什么是向量图表?如何用 Highcharts 快速创建一个笛卡尔坐标图/矢量图?
javascript·开发文档·highcharts·图表开发·向量图·矢量图表·笛卡尔坐标图
NEXT0611 小时前
React 闭包陷阱深度解析:从词法作用域到快照渲染
前端·react.js·面试
脱离语言12 小时前
Jeecg3.8.2 前端经验汇总
开发语言·前端·javascript