• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

TSXvue3 + element-ui + tsx 通用表格组件

武飞扬头像
林大大哟
帮助1

简介: 基于 vue3 el-table 封装的通用表格组件 的 tsx写法,想要参考模板写法的可以到我另一篇博客喔~

TS vue3.2 vite2 element-plus 通用表格组件封装

话不多说,本组件分为四部分:

1、CommonTable.module.scss 文件为组件样式文件

  1.  
    :global {
  2.  
    .common-table {
  3.  
    .el-table__header,
  4.  
    .el-table__body {
  5.  
    margin: 0;
  6.  
    }
  7.  
    .el-table::before {
  8.  
    height: 0;
  9.  
    }
  10.  
    .el-button {
  11.  
    padding: 0;
  12.  
    border: none;
  13.  
    margin: 0 4px;
  14.  
    padding: 0 4px 0 8px;
  15.  
    border-left: 1px solid #e2e2e2;
  16.  
    font-size: 14px;
  17.  
    min-height: 14px;
  18.  
    &:first-child {
  19.  
    border-left: none;
  20.  
    }
  21.  
    }
  22.  
    .el-button .el-button {
  23.  
    margin-left: 0;
  24.  
    }
  25.  
    .btn-right div {
  26.  
    margin-right: 5px;
  27.  
    }
  28.  
    .btn-right div:empty {
  29.  
    margin-right: 0px;
  30.  
    }
  31.  
    //斑马纹表格背景色
  32.  
    .el-table .even-row {
  33.  
    --el-table-tr-background-color: #f5fafb;
  34.  
    }
  35.  
    .el-table .odd-row {
  36.  
    --el-table-tr-background-color: #ffffff;
  37.  
    }
  38.  
    .el-table--border::after,
  39.  
    .el-table--group::after {
  40.  
    width: 0;
  41.  
    }
  42.  
    .el-table__fixed-right::before,
  43.  
    .el-table__fixed::before {
  44.  
    background-color: transparent;
  45.  
    }
  46.  
    .custom-table-header {
  47.  
    th {
  48.  
    background-color: #fff4d9 !important;
  49.  
    }
  50.  
    }
  51.  
    .progress-line {
  52.  
    .el-progress-bar__outer {
  53.  
    height: 16px !important;
  54.  
    }
  55.  
    .el-progress-bar__outer,
  56.  
    .el-progress-bar__inner {
  57.  
    border-radius: 0 !important;
  58.  
    }
  59.  
    }
  60.  
    .text-no-wrap {
  61.  
    cursor: pointer;
  62.  
    display: inline;
  63.  
    }
  64.  
    .el-table {
  65.  
    td.el-table__cell div,
  66.  
    th.el-table__cell>.cell {
  67.  
    font-size: 14px;
  68.  
    }
  69.  
    th.el-table__cell>.cell {
  70.  
    font-weight: normal;
  71.  
    }
  72.  
    .cell {
  73.  
    padding: 0 10px;
  74.  
    line-height: 39px;
  75.  
    }
  76.  
    .el-table__header-wrapper .checkBoxRadio .el-checkbox {
  77.  
    display: none;
  78.  
    }
  79.  
    .el-checkbox {
  80.  
    display: flex;
  81.  
    align-items: center;
  82.  
    justify-content: center;
  83.  
    }
  84.  
    .table-img {
  85.  
    width: 60px;
  86.  
    height: 60px;
  87.  
    object-fit: cover;
  88.  
    padding: 6px 0;
  89.  
    display: flex;
  90.  
    align-items: center;
  91.  
    margin: 0 auto;
  92.  
    justify-content: center;
  93.  
    }
  94.  
    }
  95.  
    .el-table--small .el-table__cell {
  96.  
    padding: 0;
  97.  
    }
  98.  
    .el-dropdown-menu__item {
  99.  
    padding: 5px 10px !important;
  100.  
    .el-button {
  101.  
    width: 100%;
  102.  
    text-align: center;
  103.  
    padding: 0 8px;
  104.  
    margin: 0;
  105.  
    }
  106.  
    }
  107.  
    .flex-box {
  108.  
    display: flex;
  109.  
    flex-flow: row nowrap;
  110.  
    justify-content: flex-start;
  111.  
    .item {
  112.  
    margin: 0 10px;
  113.  
    }
  114.  
    }
  115.  
    }
  116.  
    }
学新通

2、CommonTable.module.ts为组件逻辑文件

  1.  
    import {
  2.  
    ref,
  3.  
    watch,
  4.  
    nextTick
  5.  
    } from 'vue';
  6.  
     
  7.  
    export default function(props, emit, CommonTable) {
  8.  
    const curPageCheck = ref([])
  9.  
    watch(() => props.data, () => {
  10.  
    if (props.showCheckBox || props.turnRadio) {
  11.  
    nextTick(() => {
  12.  
    CommonTable.value.clearSelection()
  13.  
    curPageCheck.value = []
  14.  
    if (props.showCheckBox && props.turnRadio) {
  15.  
    props.data.filter((item) => {
  16.  
    if (item.id === props.selectedIdArr[0]) {
  17.  
    CommonTable.value.toggleRowSelection(item, true)
  18.  
    }
  19.  
    })
  20.  
    } else if (props.showCheckBox) {
  21.  
    props.data.filter((item) => {
  22.  
    if (props.selectedIdArr.includes(item.id)) {
  23.  
    CommonTable.value.toggleRowSelection(item, true)
  24.  
    curPageCheck.value.push(item.id)
  25.  
    }
  26.  
    })
  27.  
    }
  28.  
    })
  29.  
    }
  30.  
    }, {
  31.  
    immediate: true
  32.  
    })
  33.  
    watch(() => props.selectedIdArr, (val) => {
  34.  
    if (props.showCheckBox || props.turnRadio) {
  35.  
    nextTick(() => {
  36.  
    CommonTable.value.clearSelection()
  37.  
    curPageCheck.value = []
  38.  
    if (props.showCheckBox && props.turnRadio) {
  39.  
    props.data.filter((item) => {
  40.  
    if (item.id === val[0]) {
  41.  
    CommonTable.value.toggleRowSelection(item, true)
  42.  
    }
  43.  
    })
  44.  
    } else if (props.showCheckBox) {
  45.  
    props.data.filter((item) => {
  46.  
    if (val.includes(item.id)) {
  47.  
    CommonTable.value.toggleRowSelection(item, true)
  48.  
    curPageCheck.value.push(item.id)
  49.  
    }
  50.  
    })
  51.  
    }
  52.  
    })
  53.  
    }
  54.  
    }, {
  55.  
    immediate: true
  56.  
    })
  57.  
    const methods = {
  58.  
    /**
  59.  
    * prop 单值 或者 数组过滤(此处为针对时间组,不作为通用处理)
  60.  
    */
  61.  
    propFilter(prop, row) {
  62.  
    const res = prop.reduce((total, cur) => {
  63.  
    if (row[cur]) {
  64.  
    return (total = row[cur] '~')
  65.  
    } else {
  66.  
    return ''
  67.  
    }
  68.  
    }, '')
  69.  
    return res ? res.replace(/~$/, '') : ''
  70.  
    },
  71.  
    handleTableButton(row, type) {
  72.  
    emit('operation', row, type);
  73.  
    },
  74.  
    /**
  75.  
    * 后续扩展位
  76.  
    * @param {*} methods
  77.  
    * @param {*} row
  78.  
    */
  79.  
    handleClickon(methods, row) {
  80.  
    emit(methods, { methods, row })
  81.  
    },
  82.  
    handleSelectionChange(val) {
  83.  
    if (props.showCheckBox && props.turnRadio) {
  84.  
    // 选择项大于1时
  85.  
    if (val.length > 1) {
  86.  
    const del_row = val.shift()
  87.  
    CommonTable.value.toggleRowSelection(del_row, false)
  88.  
    }
  89.  
    }
  90.  
    // 全选
  91.  
    if (props.showCheckBox && props.selectedIdArr) {
  92.  
    if (props.turnRadio) {
  93.  
    emit('handle-selection-change', val)
  94.  
    } else {
  95.  
    // 一般复选框都是走到这一步
  96.  
    emit('handle-selection-change', val)
  97.  
    }
  98.  
    } else {
  99.  
    emit('handle-selection-change', val)
  100.  
    }
  101.  
    },
  102.  
    getRowKeys(row) {
  103.  
    return row.id
  104.  
    },
  105.  
    selectAll(val) {
  106.  
    if (props.showCheckBox && props.turnRadio) {
  107.  
    // 选择项大于1时
  108.  
    if (val.length > 1) {
  109.  
    val.length = 1
  110.  
    }
  111.  
    }
  112.  
    emit('handle-selection-change', val)
  113.  
    },
  114.  
    // 斑马纹表格背景色
  115.  
    tabRowClassName({ rowIndex }) {
  116.  
    const index = rowIndex 1
  117.  
    if (index % 2 === 0) {
  118.  
    return 'even-row'
  119.  
    } else {
  120.  
    return 'odd-row'
  121.  
    }
  122.  
    },
  123.  
    cellClassName({ row, columnIndex }) {
  124.  
    if (row.confirmTag === 2 && columnIndex < props.tableLabel.length) {
  125.  
    return 'height_light_cell'
  126.  
    } else {
  127.  
    return ''
  128.  
    }
  129.  
    },
  130.  
    buttonDisabled(item, row) {
  131.  
    if (typeof item.disabled === 'function') return item.disabled(row) || false
  132.  
    if (!item.disabled) return item.disabled
  133.  
    },
  134.  
    /**
  135.  
    * 单选框选中事件
  136.  
    */
  137.  
    rowClick(row) {
  138.  
    emit('rowClick', row)
  139.  
    }
  140.  
    }
  141.  
    return {
  142.  
    methods
  143.  
    }
  144.  
    }
学新通

3、CommonTable.tsx为组件渲染文件

  1.  
    import {
  2.  
    defineComponent,
  3.  
    ref,
  4.  
    PropType
  5.  
    } from 'vue';
  6.  
    import {
  7.  
    TableLabel,
  8.  
    TableDataItem
  9.  
    } from './types';
  10.  
    import useModule from './CommonTable.module';
  11.  
    import './CommonTable.module.scss';
  12.  
     
  13.  
    export default defineComponent({
  14.  
    name: 'CommonTable',
  15.  
    props: {
  16.  
    /**
  17.  
    * 表格最高高度
  18.  
    */
  19.  
    maxHeight: {
  20.  
    type: [String, Number],
  21.  
    default: 'auto'
  22.  
    },
  23.  
    /**
  24.  
    * 表格自定义属性展示
  25.  
    */
  26.  
    tableLabel: {
  27.  
    type: Array as PropType<TableLabel[]>,
  28.  
    default: () => []
  29.  
    },
  30.  
    /**
  31.  
    * 表格数据源
  32.  
    */
  33.  
    data: {
  34.  
    type: Array as PropType<TableDataItem[]>,
  35.  
    default: () => []
  36.  
    },
  37.  
    /**
  38.  
    * 配置需要显示的操作菜单
  39.  
    */
  40.  
    option: {
  41.  
    type: Object,
  42.  
    default: () => {}
  43.  
    },
  44.  
    showCheckBox: {
  45.  
    // 配置是否显示全选(复选框)
  46.  
    type: Boolean,
  47.  
    default: false
  48.  
    },
  49.  
    /**
  50.  
    * 是否显示索引
  51.  
    */
  52.  
    showIndex: {
  53.  
    type: Boolean,
  54.  
    default: false
  55.  
    },
  56.  
    turnRadio: {
  57.  
    type: Boolean,
  58.  
    default: false
  59.  
    },
  60.  
    selectedIdArr: {
  61.  
    type: Array as PropType<number[] | string[]>,
  62.  
    default: () => []
  63.  
    },
  64.  
    /**
  65.  
    * 是否 隐藏文字过长
  66.  
    */
  67.  
    overflowText: {
  68.  
    type: Boolean,
  69.  
    default: false
  70.  
    },
  71.  
    /**
  72.  
    * 加载提示
  73.  
    */
  74.  
    loading: {
  75.  
    type: Boolean,
  76.  
    default: false
  77.  
    },
  78.  
    /**
  79.  
    * 是否保持之前复选框的数据
  80.  
    */
  81.  
    keep: {
  82.  
    type: Boolean,
  83.  
    default: false
  84.  
    },
  85.  
    /**
  86.  
    * 动态绑定 key 值
  87.  
    */
  88.  
    keyId: {
  89.  
    type: String,
  90.  
    default: 'id'
  91.  
    },
  92.  
    /**
  93.  
    * 行内自定义样式配置
  94.  
    */
  95.  
    rowStyle: {
  96.  
    type: Object,
  97.  
    default: () => {
  98.  
    return {
  99.  
    height: '40px'
  100.  
    }
  101.  
    }
  102.  
    },
  103.  
    /**
  104.  
    * 是否展示展开按钮
  105.  
    */
  106.  
    showExpand: {
  107.  
    type: Boolean,
  108.  
    default: false
  109.  
    }
  110.  
    },
  111.  
    setup(props, { emit, slots }) {
  112.  
    const CommonTable = ref(null)
  113.  
    const {
  114.  
    methods
  115.  
    } = useModule(props, emit, CommonTable)
  116.  
    return () => (
  117.  
    <div v-loading={props.loading}>
  118.  
    <el-table
  119.  
    class='common-table'
  120.  
    ref={CommonTable}
  121.  
    data={props.data}
  122.  
    border
  123.  
    max-height={props.maxHeight}
  124.  
    row-class-name={methods.tabRowClassName}
  125.  
    row-style={props.rowStyle}
  126.  
    cell-class-name={methods.cellClassName}
  127.  
    header-row-class-name='custom-table-header'
  128.  
    row-key={props.keyId}
  129.  
    on-select={methods.handleSelectionChange}
  130.  
    on-select-all={methods.handleSelectionChange}
  131.  
    >
  132.  
    {
  133.  
    props.showCheckBox && <el-table-column
  134.  
    key='showCheckBox'
  135.  
    width='55'
  136.  
    type='selection'
  137.  
    reserve-selection={props.keep}
  138.  
    class-name={props.turnRadio ? 'checkBoxRadio' : ''}
  139.  
    align='center'
  140.  
    />
  141.  
    }
  142.  
    {
  143.  
    props.showExpand && <el-table-column
  144.  
    key='showExpand'
  145.  
    type='expand'
  146.  
    scopedSlots={{
  147.  
    default: scope => {
  148.  
    return <fragment row={scope.row}>
  149.  
    {
  150.  
    slots.expand?.()
  151.  
    }
  152.  
    </fragment>
  153.  
    }
  154.  
    }}
  155.  
    >
  156.  
    </el-table-column>
  157.  
    }
  158.  
    {
  159.  
    props.showIndex && <el-table-column
  160.  
    align='center'
  161.  
    label='序号'
  162.  
    width='50'
  163.  
    scopedSlots={{
  164.  
    default: scope => {
  165.  
    return scope.$index 1
  166.  
    }
  167.  
    }}
  168.  
    >
  169.  
    </el-table-column>
  170.  
    }
  171.  
    {
  172.  
    props.tableLabel.map((item: TableLabel) => {
  173.  
    return <el-table-column
  174.  
    key={item[props.keyId]}
  175.  
    width={item.width ?? ''}
  176.  
    align={item.align ?? 'center'}
  177.  
    label={item.label}
  178.  
    show-overflow-tooltip={props.overflowText}
  179.  
    fixed={item.fixed}
  180.  
    prop={item.prop}
  181.  
    scopedSlots={{
  182.  
    default: (scope) => {
  183.  
    if (item.render) {
  184.  
    return <div
  185.  
    style='cursor: pointer'
  186.  
    onClick={() => item.methods && methods.handleClickon(item.methods, scope.row)}
  187.  
    domPropsInnerHTML={item.render(scope.row)}
  188.  
    >
  189.  
    </div>
  190.  
    } else {
  191.  
    return <div
  192.  
    class='text-no-wrap'
  193.  
    onClick={() => item.methods && methods.handleClickon(item.methods, scope.row)}>
  194.  
    {
  195.  
    Object.prototype.toString.call(item.prop) === '[object Array]' ? methods.propFilter(item.prop, scope.row) : (scope.row[item.prop] ?? '--')
  196.  
    }
  197.  
    </div>
  198.  
    }
  199.  
    }
  200.  
    }}
  201.  
    >
  202.  
    </el-table-column>
  203.  
    })
  204.  
    }
  205.  
    {
  206.  
    props.option && <el-table-column
  207.  
    width={props.option.width}
  208.  
    label={props.option.label}
  209.  
    fixed={props.option.fixed}
  210.  
    align={props.option.align ?? 'center'}
  211.  
    scopedSlots={{
  212.  
    default: scope => {
  213.  
    return props.option.children.length && <div
  214.  
    class='flex-box'
  215.  
    >
  216.  
    {
  217.  
    props.option.children.map(item => {
  218.  
    return <el-tooltip
  219.  
    class='item'
  220.  
    effect='light'
  221.  
    popper-class='yxp-tooltip-primary'
  222.  
    content={item.label}
  223.  
    placement='top'
  224.  
    >
  225.  
    <i
  226.  
    class={['yxp-tooltip-icon', item.icon]}
  227.  
    plain='true'
  228.  
    onClick={() => methods.handleTableButton(scope.row, item.methods)}
  229.  
    />
  230.  
    </el-tooltip>
  231.  
    })
  232.  
    }
  233.  
    </div>
  234.  
    }
  235.  
    }}
  236.  
    >
  237.  
    </el-table-column>
  238.  
    }
  239.  
    </el-table>
  240.  
    </div>
  241.  
    )
  242.  
    }
  243.  
    })
学新通

4、types.ts为类型定义文件

  1.  
    /** 表格行数据类型 */
  2.  
    export interface TableDataItem {
  3.  
    xxx: number;
  4.  
    }
  5.  
     
  6.  
    /** 表格基础类型配置 */
  7.  
    interface BasicLabel {
  8.  
    label: string; // 标题
  9.  
    width?: number | string; // 宽度
  10.  
    fixed?: string; // 固定位置
  11.  
    align?: string; // 行排列
  12.  
    visible?: boolean; // 是否展示
  13.  
    }
  14.  
     
  15.  
    /** 表格顶部类型配置 */
  16.  
    export interface TableLabel extends BasicLabel {
  17.  
    prop: string;
  18.  
    methods?: string;
  19.  
    render?: render;
  20.  
    mode?: string;
  21.  
    selects?: Select[]
  22.  
    }
  23.  
     
  24.  
    /** 表格顶部自定义函数类型 */
  25.  
    interface render {
  26.  
    (row: TableDataItem): string
  27.  
    }
  28.  
     
  29.  
    /** 表格操作栏类型 */
  30.  
    export interface OptionLabel extends BasicLabel {
  31.  
    prop?: string;
  32.  
    children: OptionChild[]
  33.  
    }
  34.  
     
  35.  
    /** 表格操作栏子选项类型 */
  36.  
    export interface OptionChild {
  37.  
    label: string; // 标题
  38.  
    icon: string; // icon图标
  39.  
    method: string; // 执行方法
  40.  
    permission: string | string[]; // 权限
  41.  
    }
学新通

5、组件调用方式 

组件调用:

  1.  
    <CommonTable
  2.  
    show-index
  3.  
    show-check-box={true}
  4.  
    loading={loading.value}
  5.  
    max-height={550}
  6.  
    table-label={tableHeaderData}
  7.  
    data={tableData.value}
  8.  
    option={tableOptionsData}
  9.  
    on-operation={methods.operationHandler}
  10.  
    on-handle-selection-change={methods.handleSelectionChange}
  11.  
    />

 属性及方法使用说明:

  1.  
    /** 表格头部配置 */
  2.  
    const tableHeaderData = [
  3.  
    {
  4.  
    label: '文件大小',
  5.  
    prop: 'size',
  6.  
    width: '100',
  7.  
    render(row) {
  8.  
    return xxx
  9.  
    }
  10.  
    }
  11.  
    ]
  12.  
     
  13.  
    /** 表格操作栏配置 */
  14.  
    const tableOptionsData = {
  15.  
    label: '操作',
  16.  
    width: '150',
  17.  
    fixed: 'right',
  18.  
    children: [
  19.  
    {
  20.  
    label: '操作记录',
  21.  
    icon: 'xxx',
  22.  
    methods: 'record',
  23.  
    permission: ''
  24.  
    }
  25.  
    ]
  26.  
    }
  27.  
     
  28.  
    const methods = {
  29.  
    /**
  30.  
    * 操作栏分发逻辑
  31.  
    * @param row 当行数据
  32.  
    * @param type 分发函数名
  33.  
    */
  34.  
    operationHandler(row: TableDataItem, type: string) {
  35.  
    if (type === 'record') { // 操作记录
  36.  
    }
  37.  
    },
  38.  
    /**
  39.  
    * 复选框处理回调
  40.  
    * @param val 复选框选中的数据
  41.  
    */
  42.  
    handleSelectionChange(val: TableDataItem[]) {
  43.  
    multipleSelection.value = val
  44.  
    }
  45.  
    }
学新通

有不懂的可以底下评论噢~

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfhjgg
系列文章
更多 icon
同类精品
更多 icon
继续加载