赞
踩
介绍: 这是基于 vue3 + el-table 封装的通用表格组件 的 模板写法,想要参考tsx写法的可以到我另一篇博客喔~
【通用表格组件】vue3 + element-ui + tsx 实现通用表格组件
这里通用表格,和上一篇通用表单一样的(表格组件都在我博客里),配置完全可控,然后每个el-table-column 都是通过传入的数组来循环便利渲染,大部分常用实现也写在了下面,无法具体实现或需要你自己自定义开发的,都可以通过render来开发。
- <CommonTable
- show-index
- show-check-box
- key-id="id"
- :loading="loading"
- :max-height="390"
- :table-label="tableHeaderData"
- :row-class-name="tableSortRowClassName"
- :data="tableData"
- :option="tableOptionsData"
- @operation="operationHandler"
- @handle-selection-change="handleSelectionChange"
- />
export const tableHeaderData = [ { label: '部门名称/用户名称', prop: 'name', }, { label: '部门负责人', prop: 'contactPerson', }, ] export const tableOptionsData = { label: '操作', width: '300', fixed: 'right', children: [ { label: '查看制作详情', icon: 'el-icon-view', methods: 'view', permission: 'xxx', render(row) { return row.status !== 0 } } ] }
- <template>
- <div v-loading="loading">
- <el-table
- ref="table"
- v-bind="{ ...props }"
- :data="data"
- style="width: 100%"
- :row-class-name="tabRowClassName"
- @select="handleSelectionChange"
- :row-style="rowStyle"
- @select-all="handleSelectionChange"
- :cell-class-name="cellClassName"
- header-row-class-name="custom-table-header"
- :default-expand-all="expendAll"
- row-key="id"
- :max-height="maxHeight"
- >
- <!-- 单选框 -->
- <el-table-column
- v-if="showCheckBoX"
- width="55"
- type="selection"
- :reserve-selection="keep"
- :class-name="turnRadio ? `checkBoxRadio` : ``"
- align="center"
- ></el-table-column>
- <!-- 序号 -->
- <el-table-column v-if="showTypeIndex" align="center" label="序号" width="50">
- <template #default="{ $index }">{{ $index + 1 }}</template>
- </el-table-column>
- <!-- 表格 -->
- <el-table-column
- v-for="item in tableLabel.filter((item) => item.label)"
- :width="item.width ? item.width : ''"
- :key="item[keyId]"
- :align="!!item.align ? item.align : 'center'"
- :label="item.label"
- :show-overflow-tooltip="overflowText"
- :fixed="item.fixed"
- :prop="item.prop"
- >
- <template #default="{ row }">
- <template v-if="item.Image">
- <div>
- <el-image class="table-img" :src="row.attachment" :preview-src-list="[row.attachment]">
- <template #error>
- <span>无</span>
- </template>
- </el-image>
- </div>
- </template>
- <template v-else-if="item.render">
- <div style="cursor: pointer" @click="!!item.methods && handleClickon(item.methods, row)" v-html="item.render(row)"></div>
- </template>
- <template v-else-if="item.format">
- <div v-if="typeof item.format === 'function'">{{ item.format(row[item.prop], row, item) }}</div>
- </template>
-
- <template v-else>
- <div class="text-no-wrap" @click="!!item.methods && handleClickon(item.methods, row)">
- {{ Object.prototype.toString.call(item.prop) == '[object Array]' ? propFilter(item.prop, row) : row[item.prop] }}
- </div>
- </template>
- </template>
- </el-table-column>
- <el-table-column v-if="!!option" :width="option.width" :label="option.label" :fixed="option.fixed" align="center">
- <template #default="scope" v-if="!!option.children">
- <!-- 常规正常情况 -->
- <el-button
- type="text"
- v-for="(item, index) in option.children"
- :key="index"
- v-show="!buttonHidden(item, scope.row)"
- v-bind="{ ...item.props }"
- :disabled="buttonDisabled(item, scope.row)"
- @click="handleTableButton(item.methods, scope.row, index, scope.$index)"
- :class="['btn-' + item.methods, 'btn-right']"
- size="mini"
- >
- <template v-if="item.render">
- <div v-html="item.render(scope.row)"></div>
- </template>
- {{ !!item.label ? item.label : '' }}
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </template>
-
- <script lang="ts">
- import { defineComponent, computed, PropType, ref, onMounted, nextTick, reactive, watch } from 'vue'
- import { useStore } from 'store/index'
- import { Utils } from '@/utils'
- import { isNumber } from '@/utils/is'
-
- interface PageInfo {
- pageIndex: number
- totalCount: number
- pageSize: number
- pageArr?: []
- [ket: string]: any
- }
-
- interface ColumnI {
- label: string
- prop: string
- width?: string | number
- }
-
- interface TableOption {
- label: string
- methods: string
- props: object
- style: object
- render: Function
- }
-
- interface TableOptions {
- label: string
- width: string | number
- fixed: boolean
- popoverWidth?: number | string
- children: Array<TableOption>
- }
-
- interface Props {
- maxHeight: string | number
- stateArr: Array<any>
- tableLabel: Array<ColumnI>
- option: TableOption
- showCheckBoX: boolean
- showTypeIndex: boolean
- turnRadio: boolean
- selectedIdArr: Array<any>
- pageInfo: PageInfo
- showPagination: boolean
- overflowText: boolean
- loading: boolean
- keep: boolean
- keyId: string
- data: Array<any>
- expendAll: boolean
- }
-
- export default defineComponent({
- name: 'CommonTable',
- props: {
- maxHeight: {
- type: [String, Number],
- default: 600
- },
- stateArr: {
- type: Array,
- default: () => {
- return []
- }
- },
- tableLabel: {
- // 表格展示
- type: Array as PropType<Array<ColumnI>>,
- default: () => {
- return []
- }
- },
- data: {
- // 数据源
- type: Array as PropType<Array<any>>,
- default: () => {
- return []
- }
- },
- option: {
- // 配置需要显示的操作菜单
- type: Object as PropType<TableOption>
- },
- showCheckBoX: {
- // 配置是否显示全选(复选框)
- type: Boolean,
- default: false
- },
- showTypeIndex: {
- type: Boolean,
- default: false
- },
- turnRadio: {
- type: Boolean,
- default: false
- },
- selectedIdArr: {
- type: Array,
- default: []
- },
- pageInfo: {
- // 配置分页
- type: Object,
- default: () => {
- return {
- pageIndex: 1,
- totalCount: 0,
- pageSize: 10,
- pageArr: []
- }
- }
- },
- showPagination: {
- // 是否隐藏 分页显示
- type: Boolean,
- default: true
- },
- overflowText: {
- // 是否 隐藏文字过长
- type: Boolean,
- default: false
- },
- loading: {
- // loading 配置
- type: Boolean,
- default: false
- },
- keep: {
- type: Boolean,
- default: false
- },
- keyId: {
- // 动态绑定 key 值
- type: String,
- default: 'id'
- },
- props: {
- // 表格参数配置
- type: Object,
- default: function () {
- return {
- 'show-header': true, // 显示表头e
- 'highlight-current-row': false, // 是否要高亮当前行
- 'tooltip-effect': 'dark', //
- 'max-height': 'auto', // Table 的最大高度。合法的值为数字或者单位为 px 的高度。
- 'empty-text': '没有数据', // 空数据显示状态
- 'element-loading-text': '加载中', // loading 加载
- 'header-cell-style': {
- background: '#F2F4F7',
- color: '#333',
- fontSize: '13px'
- }, // 表头样式
- border: false, // 是否带有纵向边框
- fit: true, // 列的宽度是否自撑开
- stripe: false // 是否显示斑马纹
- }
- }
- },
- rowStyle: {
- type: Object,
- default: () => {
- return {
- height: '40px'
- }
- }
- },
- expendAll: {
- type: Boolean,
- default: false
- },
- /**
- * 行内自定义class
- */
- rowClassName: {
- type: Function,
- default: () => {
- return () => {}
- }
- }
- },
- setup(props: any, { emit }) {
- watch(
- () => props.data,
- () => {
- if (props.showCheckBoX || props.turnRadio) {
- nextTick(() => {
- table.value.clearSelection()
- curPageCheck.value = []
- if (props.showCheckBoX && props.turnRadio) {
- props.data.filter((item: any) => {
- if (item.id == props.selectedIdArr[0]) {
- table.value.toggleRowSelection(item, true)
- }
- })
- } else if (props.showCheckBoX) {
- props.data.filter((item: any) => {
- if (props.selectedIdArr.includes(item.id)) {
- table.value.toggleRowSelection(item, true)
- curPageCheck.value.push(item.id)
- }
- })
- }
- })
- }
- },
- {
- deep: true,
- immediate: true
- }
- )
-
- watch(
- () => props.selectedIdArr,
- (val) => {
- if (props.showCheckBoX || props.turnRadio) {
- nextTick(() => {
- table.value.clearSelection()
- curPageCheck.value = []
- if (props.showCheckBoX && props.turnRadio) {
- props.data.filter((item: any) => {
- if (item.id == val[0]) {
- table.value.toggleRowSelection(item, true)
- }
- })
- } else if (props.showCheckBoX) {
- props.data.filter((item: any) => {
- if (val.includes(item.id)) {
- table.value.toggleRowSelection(item, true)
- curPageCheck.value.push(item.id)
- }
- })
- }
- })
- }
- },
- {
- deep: true
- }
- )
- /**
- * prop 单值 或者 数组过滤(此处为针对时间组,不作为通用处理)
- */
- const propFilter = (prop: [Array<any> | object], row: any) => {
- let res = prop.reduce((total: string, cur: any) => {
- if (row[cur]) {
- return (total += row[cur] + '~')
- } else {
- return ''
- }
- }, '')
- // console.log(res)
- return res ? res.replace(/~$/, '') : ''
- }
- const handleTableButton = (methods: any, row: object, index: number, rowIndex: number) => {
- // 按钮事件
- emit('handleTableButton', { methods, row, index, rowIndex })
- }
- const handleClickon = (methods: any, row: object) => {
- if (typeof methods !== 'string') throw '方法名错误'
- // 数据操作
- emit(methods, { methods, row })
- }
- const curPageCheck = ref<Array<any>>([])
- const handleSelectionChange = (val: Array<any>) => {
- let arr = val.map((item) => parseInt(item.id))
- let compare = Utils.compareArray(curPageCheck.value, arr)
- if (props.showCheckBoX && props.turnRadio) {
- // 选择项大于1时
- if (val.length > 1) {
- let del_row = val.shift()
- table.value.toggleRowSelection(del_row, false)
- }
- }
- // 全选
- if (props.showCheckBoX && props.selectedIdArr) {
- if (props.turnRadio) {
- emit('handleSelectionChange', val)
- } else {
- emit('handleSelectionChange', val, compare)
- }
- } else {
- emit('handleSelectionChange', val)
- }
- }
- const getList = (pages: any) => {
- let { page, limit } = pages
- if (!isNumber(page)) {
- page = page.value
- }
- if (!isNumber(limit)) {
- limit = limit.value
- }
- const pageInfo = {
- page,
- limit
- }
- emit('handleGetList', pageInfo)
- }
- const getRowKeys = (row: any) => {
- return row.id
- }
- const table = ref<any>(null)
-
- const selectAll = (val: any) => {
- if (props.showCheckBoX && props.turnRadio) {
- // 选择项大于1时
- if (val.length > 1) {
- val.length = 1
- }
- }
- emit('handleSelectionChange', val)
- }
-
- //斑马纹表格背景色
- const tabRowClassName = ({ row, rowIndex }: any) => {
- let index = rowIndex + 1
- if (index % 2 == 0) {
- return 'even-row'
- } else {
- return 'odd-row'
- }
- return ''
- }
-
- const cellClassName = ({ row, column, rowIndex, columnIndex }: any) => {
- if (row.confirmTag === 2 && columnIndex < (props as any).tableLabel.length) {
- return 'height_light_cell'
- } else {
- return ''
- }
- }
-
- const buttonHidden = (item: any, row?: any) => {
- if (typeof item.hidden === 'function') return item.hidden(row) || false
- if (!item.hidden) return item.hidden
- }
-
- const buttonDisabled = (item: any, row?: any) => {
- if (typeof item.disabled === 'function') return item.disabled(row) || false
- if (!item.disabled) return item.disabled
- }
-
- const store = useStore()
- const buttonType = computed(() => store.state.app.buttonType)
- const showVertical = ref<boolean>(false)
- /**
- * 单选框选中事件
- */
- const rowClick = (row: any): void => {
- emit('rowClick', row)
- }
- const radioId = ref<number | string>(-1)
- return {
- propFilter,
- handleTableButton,
- handleClickon,
- handleSelectionChange,
- getList,
- getRowKeys,
- tabRowClassName,
- cellClassName,
- buttonHidden,
- buttonDisabled,
- buttonType,
- showVertical,
- table,
- radioId,
- rowClick,
- selectAll
- }
- }
- })
- </script>
-
- <style lang="scss" scoped>
- ::v-deep .el-table__header,
- ::v-deep .el-table__body {
- margin: 0;
- }
-
- .scrollBar {
- @include scrollBar;
- }
-
- ::v-deep .el-table::before {
- height: 0;
- }
-
- ::v-deep .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;
- }
- }
-
- ::v-deep .el-button + .el-button {
- margin-left: 0;
- }
-
- .btn-see {
- color: #39a6ff;
- }
-
- .btn-handel {
- color: #41a4bd;
- }
-
- .btn-edit {
- color: #fcb0fb;
- }
-
- .btn-delete,
- .btn-del {
- color: #fd9090;
- }
-
- .btn-revoke {
- color: #ffa913;
- }
-
- ::v-deep .btn-right div {
- margin-right: 5px;
- }
-
- .btn-right div:empty {
- margin-right: 0px;
- }
-
- //斑马纹表格背景色
- ::v-deep(.el-table) .even-row {
- --el-table-tr-background-color: #f5fafb;
- }
-
- ::v-deep(.el-table) .odd-row {
- --el-table-tr-background-color: #ffffff;
- }
-
- .el-table--border::after,
- .el-table--group::after {
- width: 0;
- }
-
- ::v-deep .el-table td,
- th.is-leaf {
- border: none;
- }
-
- ::v-deep .el-table__fixed-right::before,
- .el-table__fixed::before {
- background-color: transparent;
- }
-
- ::v-deep .custom-table-header {
- th {
- background-color: #62c4ee !important;
- color: #fff !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 {
- @include text-no-wrap;
- cursor: pointer;
- display: inline;
- }
-
- ::v-deep(.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;
- }
- }
-
- ::v-deep(.el-table--small .el-table__cell) {
- padding: 0;
- }
-
- ::v-deep(.el-dropdown-menu__item) {
- padding: 0 !important;
- .el-button {
- width: 100%;
- text-align: center;
- padding: 0 8px;
- margin: 0;
- }
- }
- </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。