【TSX】vue3 + element-ui + tsx 通用表格组件

这篇具有很好参考价值的文章主要介绍了【TSX】vue3 + element-ui + tsx 通用表格组件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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

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

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

:global {
  .common-table {
    .el-table__header,
    .el-table__body {
      margin: 0;
    }
    .el-table::before {
      height: 0;
    }
    .el-button {
      padding: 0;
      border: none;
      margin: 0 4px;
      padding: 0 4px 0 8px;
      border-left: 1px solid #e2e2e2;
      font-size: 14px;
      min-height: 14px;
      &:first-child {
        border-left: none;
      }
    }
    .el-button+.el-button {
      margin-left: 0;
    }
    .btn-right div {
      margin-right: 5px;
    }
    .btn-right div:empty {
      margin-right: 0px;
    }
    //斑马纹表格背景色
    .el-table .even-row {
      --el-table-tr-background-color: #f5fafb;
    }
    .el-table .odd-row {
      --el-table-tr-background-color: #ffffff;
    }
    .el-table--border::after,
    .el-table--group::after {
      width: 0;
    }
    .el-table__fixed-right::before,
    .el-table__fixed::before {
      background-color: transparent;
    }
    .custom-table-header {
      th {
        background-color: #fff4d9 !important;
      }
    }
    .progress-line {
      .el-progress-bar__outer {
        height: 16px !important;
      }
      .el-progress-bar__outer,
      .el-progress-bar__inner {
        border-radius: 0 !important;
      }
    }
    .text-no-wrap {
      cursor: pointer;
      display: inline;
    }
    .el-table {
      td.el-table__cell div,
      th.el-table__cell>.cell {
        font-size: 14px;
      }
      th.el-table__cell>.cell {
        font-weight: normal;
      }
      .cell {
        padding: 0 10px;
        line-height: 39px;
      }
      .el-table__header-wrapper .checkBoxRadio .el-checkbox {
        display: none;
      }
      .el-checkbox {
        display: flex;
        align-items: center;
        justify-content: center;
      }
      .table-img {
        width: 60px;
        height: 60px;
        object-fit: cover;
        padding: 6px 0;
        display: flex;
        align-items: center;
        margin: 0 auto;
        justify-content: center;
      }
    }
    .el-table--small .el-table__cell {
      padding: 0;
    }
    .el-dropdown-menu__item {
      padding: 5px 10px !important;
      .el-button {
        width: 100%;
        text-align: center;
        padding: 0 8px;
        margin: 0;
      }
    }
    .flex-box {
      display: flex;
      flex-flow: row nowrap;
      justify-content: flex-start;
      .item {
        margin: 0 10px;
      }
    }
  }
}

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

import {
  ref,
  watch,
  nextTick
} from 'vue';

export default function(props, emit, CommonTable) {
  const curPageCheck = ref([])
  watch(() => props.data, () => {
    if (props.showCheckBox || props.turnRadio) {
      nextTick(() => {
        CommonTable.value.clearSelection()
        curPageCheck.value = []
        if (props.showCheckBox && props.turnRadio) {
          props.data.filter((item) => {
            if (item.id === props.selectedIdArr[0]) {
              CommonTable.value.toggleRowSelection(item, true)
            }
          })
        } else if (props.showCheckBox) {
          props.data.filter((item) => {
            if (props.selectedIdArr.includes(item.id)) {
              CommonTable.value.toggleRowSelection(item, true)
              curPageCheck.value.push(item.id)
            }
          })
        }
      })
    }
  }, {
    immediate: true
  })
  watch(() => props.selectedIdArr, (val) => {
    if (props.showCheckBox || props.turnRadio) {
      nextTick(() => {
        CommonTable.value.clearSelection()
        curPageCheck.value = []
        if (props.showCheckBox && props.turnRadio) {
          props.data.filter((item) => {
            if (item.id === val[0]) {
              CommonTable.value.toggleRowSelection(item, true)
            }
          })
        } else if (props.showCheckBox) {
          props.data.filter((item) => {
            if (val.includes(item.id)) {
              CommonTable.value.toggleRowSelection(item, true)
              curPageCheck.value.push(item.id)
            }
          })
        }
      })
    }
  }, {
    immediate: true
  })
  const methods = {
    /**
     * prop 单值 或者 数组过滤(此处为针对时间组,不作为通用处理)
     */
    propFilter(prop, row) {
      const res = prop.reduce((total, cur) => {
        if (row[cur]) {
          return (total += row[cur] + '~')
        } else {
          return ''
        }
      }, '')
      return res ? res.replace(/~$/, '') : ''
    },
    handleTableButton(row, type) {
      if (!type) return;
      emit('operation', row, type);
    },
    /**
     * 后续扩展位
     * @param {*} methods
     * @param {*} row
     */
    handleClickon(methods, row) {
      if (!methods) return;
      emit(methods, { methods, row })
    },
    handleSelectionChange(val) {
      if (props.showCheckBox && props.turnRadio) {
        // 选择项大于1时
        if (val.length > 1) {
          const del_row = val.shift()
          CommonTable.value.toggleRowSelection(del_row, false)
        }
      }
      // 全选
      if (props.showCheckBox && props.selectedIdArr) {
        if (props.turnRadio) {
          emit('handle-selection-change', val)
        } else {
          // 一般复选框都是走到这一步
          emit('handle-selection-change', val)
        }
      } else {
        emit('handle-selection-change', val)
      }
    },
    getRowKeys(row) {
      return row.id
    },
    selectAll(val) {
      if (props.showCheckBox && props.turnRadio) {
        // 选择项大于1时
        if (val.length > 1) {
          val.length = 1
        }
      }
      emit('handle-selection-change', val)
    },
    // 斑马纹表格背景色
    tabRowClassName({ rowIndex }) {
      const classList = []
      // 默认样式配置
      const index = rowIndex + 1;
      if (index % 2 === 0) {
        classList.push('even-row');
      } else {
        classList.push('odd-row');
      }
      // 自定义样式配置
      classList.push(this.rowClassName({ row, rowIndex }))
      return classList.join(' ');
    },
    cellClassName({ row, columnIndex }) {
      if (row.confirmTag === 2 && columnIndex < props.tableLabel.length) {
        return 'height_light_cell'
      } else {
        return ''
      }
    },
    buttonDisabled(item, row) {
      if (typeof item.disabled === 'function') return item.disabled(row) || false
      if (!item.disabled) return item.disabled
    },
    /**
     * 单选框选中事件
     */
    rowClick(row) {
      emit('rowClick', row)
    }
  }
  return {
    methods
  }
}

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

import {
  defineComponent,
  ref,
  PropType
} from 'vue';
import {
  TableLabel,
  TableDataItem
} from './types';
import useModule from './CommonTable.module';
import './CommonTable.module.scss';

export default defineComponent({
  name: 'CommonTable',
  props: {
    /**
     * 表格最高高度
     */
    maxHeight: {
      type: [String, Number],
      default: 'auto'
    },
    /**
     * 表格自定义属性展示
     */
    tableLabel: {
      type: Array as PropType<TableLabel[]>,
      default: () => []
    },
    /**
     * 表格数据源
     */
    data: {
      type: Array as PropType<TableDataItem[]>,
      default: () => []
    },
    /**
     * 配置需要显示的操作菜单
     */
    option: {
      type: Object,
      default: () => {}
    },
    showCheckBox: {
      // 配置是否显示全选(复选框)
      type: Boolean,
      default: false
    },
    /**
     * 是否显示索引
     */
    showIndex: {
      type: Boolean,
      default: false
    },
    turnRadio: {
      type: Boolean,
      default: false
    },
    selectedIdArr: {
      type: Array as PropType<number[] | string[]>,
      default: () => []
    },
    /**
     * 是否 隐藏文字过长
     */
    overflowText: {
      type: Boolean,
      default: false
    },
    /**
     * 加载提示
     */
    loading: {
      type: Boolean,
      default: false
    },
    /**
     * 是否保持之前复选框的数据
     */
    keep: {
      type: Boolean,
      default: false
    },
    /**
     * 动态绑定 key 值
     */
    keyId: {
      type: String,
      default: 'id'
    },
    /**
     * 行内自定义样式配置
     */
    rowStyle: {
      type: Object,
      default: () => {
        return {
          height: '40px'
        }
      }
    },
    /**
     * 是否展示展开按钮
     */
    showExpand: {
      type: Boolean,
      default: false
    },
    /**
     * 行内自定义class
     */
    rowClassName: {
      type: Function,
      default: () => {
        return () => {}
      }
    }
  },
  setup(props, { emit, slots }) {
    const CommonTable = ref(null)
    const {
      methods
    } = useModule(props, emit, CommonTable)
    return () => (
      <div v-loading={props.loading}>
      <el-table
        class='common-table'
        ref={CommonTable}
        data={props.data}
        border
        max-height={props.maxHeight}
        row-class-name={methods.tabRowClassName}
        row-style={props.rowStyle}
        cell-class-name={methods.cellClassName}
        header-row-class-name='custom-table-header'
        row-key={props.keyId}
        on-select={methods.handleSelectionChange}
        on-select-all={methods.handleSelectionChange}
      >
        {
          props.showCheckBox && <el-table-column
            key='showCheckBox'
            width='55'
            type='selection'
            reserve-selection={props.keep}
            class-name={props.turnRadio ? 'checkBoxRadio' : ''}
            align='center'
          />
        }
        {
          props.showExpand && <el-table-column
            key='showExpand'
            type='expand'
            scopedSlots={{
              default: scope => {
                return <fragment row={scope.row}>
                  {
                    slots.expand?.()
                  }
                </fragment>
              }
            }}
          >
          </el-table-column>
        }
        {
          props.showIndex && <el-table-column
            align='center'
            label='序号'
            width='50'
            scopedSlots={{
              default: scope => {
                return scope.$index + 1
              }
            }}
          >
          </el-table-column>
        }
        {
          props.tableLabel.map((item: TableLabel) => {
            return <el-table-column
              key={item[props.keyId]}
              width={item.width ?? ''}
              align={item.align ?? 'center'}
              label={item.label}
              show-overflow-tooltip={props.overflowText}
              fixed={item.fixed}
              prop={item.prop}
              scopedSlots={{
                default: (scope) => {
                  if (item.render) {
                    return <div
                      style='cursor: pointer'
                      onClick={() => item.methods && methods.handleClickon(item.methods, scope.row)}
                      domPropsInnerHTML={item.render(scope.row)}
                    >
                    </div>
                  } else {
                    return <div
                      class='text-no-wrap'
                      onClick={() => item.methods && methods.handleClickon(item.methods, scope.row)}>
                      {
                        Object.prototype.toString.call(item.prop) === '[object Array]' ? methods.propFilter(item.prop, scope.row) : (scope.row[item.prop] ?? '--')
                      }
                  </div>
                  }
                }
              }}
            >
            </el-table-column>
          })
        }
        {
          props.option && <el-table-column
            width={props.option.width}
            label={props.option.label}
            fixed={props.option.fixed}
            align={props.option.align ?? 'center'}
            scopedSlots={{
              default: scope => {
                return props.option.children.length && <div
                  class='flex-box'
                >
                  {
                    props.option.children.map(item => {
                      return <el-tooltip
                        class='item'
                        effect='light'
                        popper-class='item.popperClass || 'default-tooltip-primary''
                        content={item.label}
                        placement='top'
                      >
                        <i
                          class={['default-tooltip-icon', item.icon]}
                          plain='true'
                          onClick={() => methods.handleTableButton(scope.row, item.methods)}
                        />
                      </el-tooltip>
                    })
                  }
                </div>
              }
            }}
            >
          </el-table-column>
        }
      </el-table>
    </div>
    )
  }
})

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

/** 表格行数据类型 */
export interface TableDataItem {
  xxx: number;
}

/** 表格基础类型配置  */
interface BasicLabel {
  label: string; // 标题
  width?: number | string; // 宽度
  fixed?: string; // 固定位置
  align?: string; // 行排列
  visible?: boolean; // 是否展示
}

/** 表格顶部类型配置  */
export interface TableLabel extends BasicLabel {
  prop: string;
  methods?: string;
  render?: render;
  mode?: string;
  selects?: Select[]
}

/** 表格顶部自定义函数类型 */
interface render {
  (row: TableDataItem): string
}

/** 表格操作栏类型 */
export interface OptionLabel extends BasicLabel {
  prop?: string;
  children: OptionChild[]
}

/** 表格操作栏子选项类型 */
export interface OptionChild {
  label: string; // 标题
  icon: string; // icon图标
  method: string; // 执行方法
  permission: string | string[]; // 权限
}

5、组件调用方式 

组件调用:

        <CommonTable
              show-index
              show-check-box={true}
              loading={loading.value}
              max-height={550}
              table-label={tableHeaderData}
              data={tableData.value}
              option={tableOptionsData}
              on-operation={methods.operationHandler}
              on-handle-selection-change={methods.handleSelectionChange}
            />

 属性及方法使用说明:

注意:如果你在使用Sortable插件想要拖动排序表格时,tableOptionsData 下的fixed参数请不要写,不然会导致无法拖动!

/** 表格头部配置  */
const tableHeaderData = [
  {
    label: '文件大小',
    prop: 'size',
    width: '100',
    render(row) {
      return xxx
    }
  }
]

/** 表格操作栏配置  */
const tableOptionsData = {
  label: '操作',
  width: '150',
  fixed: 'right',
  children: [
    {
      label: '操作记录',
      icon: 'xxx',
      methods: 'record',
      permission: ''
    }
  ]
}

const methods = {
    /**
     * 操作栏分发逻辑
     * @param row 当行数据
     * @param type 分发函数名
     */
    operationHandler(row: TableDataItem, type: string) {
      if (type === 'record') { // 操作记录
      }
    },
    /**
     * 复选框处理回调
     * @param val 复选框选中的数据
     */
    handleSelectionChange(val: TableDataItem[]) {
      multipleSelection.value = val
    }
}

有不懂的可以底下评论噢~文章来源地址https://www.toymoban.com/news/detail-606439.html

到了这里,关于【TSX】vue3 + element-ui + tsx 通用表格组件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vue中element-ui表格组件el-table封装,在table表格中插入图片

            这次写的项目是写后台管理系统这部分,对于后台管理使用vue写,用组件的话,table组件用得次数比较多,可以封装一个table组件。         1.如封装的table组件:  :prop=\\\"item.prop\\\"  :label=\\\"item.label\\\"是必须要有的,其他的可以根据自己需要写 。 2.封装之后是就是使

    2024年02月15日
    浏览(56)
  • vue | element-ui中 如何修改表格Table组件中滚动条的样式

    在Table表格中,当内容超出容器时就会出现滚动条,elemnt-ui自带的滚动条有时无法满足需求,那么我们可以通过css伪类来实现对滚动条的自定义。 滚动条由两部分组成的: 滑块:可以滑动的部分。 轨道:滚动条的轨道,即滑块的轨道。一般来说滑块的颜色比轨道的颜色深一

    2024年02月11日
    浏览(57)
  • 搭建vue3项目+按需引入element-ui框架组件

    场景 :使用vue create脚手架快速搭建vue的项目 前提 :需要安装node.js和cnpm以及yarn 并且cnpm需要设置为淘宝镜像,cnpm和yarn安装教程网上很多可以自行搜索 查看安装的版本(显示版本号说明安装成功) 1.cmd窗口跳到需要新建项目的文件夹下,使用vue create 2.我这里选择第三个Ma

    2024年02月16日
    浏览(64)
  • Vue--》如何在Vue3中书写TSX

    在vue2的时候就已经可以使用 jsx 语法,但是不是很友好,写起来是一件很痛苦的事情,所以你很少见到有人会在vue2中书写 jsx 语法,官方也不建议我们在vue2中进行书写 jsx 的代码风格: 但随着vue3版本的到来,对typescript的支持度越来越高,tsx语法也被大部分人越来越接收,所

    2024年02月04日
    浏览(36)
  • Vue3+element-ui + TS封装全局分页组件

    本文介绍了如何使用Vue3、element-ui和TypeScript封装一个全局分页组件。 在开始之前,你需要安装以下环境: Vue3 element-ui TypeScript 这个分页组件提供以下功能: 支持自定义每页显示条数 支持自定义跳转到指定页码 支持显示总页数和总条数 支持自定义样式 分页组件结构 分页组

    2024年02月12日
    浏览(61)
  • 如何在 vue3 中使用 jsx/tsx?

    我们都知道,通常情况下我们使用 vue 大多都是用的 SFC(Signle File Component)单文件组件模式,即一个组件就是一个文件,但其实 Vue 也是支持使用 JSX 来编写组件的。这里不讨论 SFC 和 JSX 的好坏,这个仁者见仁智者见智。本篇文章旨在带领大家快速了解和使用 Vue 中的 JSX 语法,好让大家

    2023年04月19日
    浏览(51)
  • VUE element-ui实现表格动态展示、动态删减列、动态排序、动态搜索条件配置、表单组件化。

        1、本组件支持列表的表头自定义配置,checkbox实现 2、本组件支持列表列排序,vuedraggable是拖拽插件,上图中字段管理里的拖拽效果 ,需要的话请自行npm install 3、本组件支持查询条件动态配置,穿梭框实现 https://download.csdn.net/download/askuld/88216937

    2024年01月16日
    浏览(62)
  • 基于vue和element-ui的表格组件,主推数据渲染,支持内容和方法灵活绑定,提供动态具名插槽自定义内容

            组件名为commonTable,主要是基于element-ui中的表格组件进行二次封装的组件,集成了常用的表格功能,除默认内容的显示外,还包括以下几点:         1. 状态的筛选和显示;         2. 操作按钮的显示和方法绑定;         3. 自定义具名插槽内容的封装;      

    2024年02月07日
    浏览(54)
  • Vue3 + Tsx 集成 ace-editor编辑器

    Ace Editor介绍 Ace Editor(全名:Ajax.org Cloud9 Editor)是一个开源的代码编辑器,旨在提供强大的代码编辑功能,通常用于构建基于Web的代码编辑应用程序。它最初由Cloud9 IDE开发,现在由开源社区维护。 主要有以下特点: 超过110种语言的语法高亮 (可以导入TextMate/Sublime Text的.

    2024年02月08日
    浏览(55)
  • Vue+Element-UI 实现前端分页功能,利用el-table和el-pagination组件实现表格前端分页

    Vue+Element-UI 实现前端分页功能,利用el-table和el-pagination组件实现表格前端分页:         当table的数据量比较大的时候,一个屏幕展示不出全部的数据,这个时候就需要分页显示。而多数情况下都是做的后端分页,就是将分页参数和查询条件一并传到后端,后端将当前页要

    2024年01月20日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包