vue3的通用表格我也封装了,是下面链接喔~
TS + vue3.2 + vite2 + element-plus 通用表格组件封装
-
- show-index
- show-check-box
- :loading="loading"
- :table-label="tableHeaderData"
- :data="tableData"
- :option="tableOptionsData"
- @operation="operationHandler"
- @handle-selection-change="handleSelectionChange"
- >
- <template slot="expand" slot-scope="{ row }">
- <making-status v-if="row.status === 1" :list="row.processList || []" />
- <div v-else class="making-status-none">
- <span>未制作span>
- div>
- template>
-
2、参数详解:
其实我定义的参数还蛮多的,基本能够把常用的功能包含进去了,我着重讲几个:
1、tableLabel:表格头部标题
有以下四个参数,最重要的是render,他的参数是从slot-scope抛出,可以进行判断显示
- {
- label: '制作格式',
- prop: 'handleType',
- width: 150,
- render(row) {
- return `${row.handleType === 1 ? '查题格式' : (row.handleType === 2 ? '拍题格式' : '未设置')}`
- }
- }
2、showCheckBox: 显示复选框
与之对应的回调函数是 @handle-selection-change,我们可以从中取得当前选中的复选框数组
3、showExpand: 拓展插槽
在 slot="expand" 即可以使用
- "expand" slot-scope="{ row }">
- // xxx
-
4、showIndex: 是否展示序号
这里序号不是你自己的自定义id喔~是当前数组索引值 + 1
5、option: 配置需要显示的操作菜单
- {
- label: '操作',
- width: '300',
- fixed: 'right',
- children: [
- {
- label: '查看制作详情',
- icon: 'el-icon-view',
- methods: 'view',
- permission: 'xxx',
- render(row) {
- return row.status !== 0
- }
- },
- {
- type: 'drop',
- icon: 'el-icon-paperclip',
- permission: 'xxx',
- children: [
- {
- label: '切题查看模式',
- methods: '1'
- },
- {
- label: '编题查看模式',
- methods: '2'
- }
- ]
- }
- ]
- }
我们主要看children里的,主要参数有4个
label: 显示名字
icon: 显示图标
permission: 即v-permission,根据按钮是否有权限再进行展示,可为字符也可为数组,这种自定义指令我就不单独写出来了,可以参考我博客,链接如下
vue学习(6)自定义指令详解及常见自定义指令,里面有个checkPermission函数,所有判断你皆可自行定义
type: 为drop 则相当于 el-dropdown,把很多按钮收缩在一起
- render: 这个和上面tableLabel不一样的是,这里render返回值为true或false来决定v-show的值(只在type不为drop生效)
- methods: 点击后回调触发的方法,由 @operation={row, type} 抛出,type即为methods对应值(只在type不为drop生效)
-
- children: drop展示子数组(label和methods与上面一致)(在type为drop生效)
3、组件源码 :
- <div v-loading="loading">
- <el-table
- ref="commonTable"
- :data="data"
- border
- :style="{
- width: '100%',
- borderBottom: maxHeight === 'auto' ? 'none' : '1px solid #e8eded'
- }"
- :max-height="maxHeight"
- :row-class-name="tabRowClassName"
- :row-style="rowStyle"
- :cell-class-name="cellClassName"
- header-row-class-name="custom-table-header"
- :row-key="keyId"
- @select="handleSelectionChange"
- @select-all="handleSelectionChange"
- >
-
- <el-table-column
- v-if="showCheckBox"
- key="showCheckBox"
- width="55"
- type="selection"
- :reserve-selection="keep"
- :class-name="turnRadio ? `checkBoxRadio` : ``"
- align="center"
- />
-
- <el-table-column
- v-if="showExpand"
- key="showExpand"
- type="expand"
- >
- <template slot-scope="{ row }">
- <slot name="expand" :row="row" />
- template>
- el-table-column>
-
- <el-table-column v-if="showIndex" align="center" label="序号" width="50">
- <template slot-scope="{ $index }">{{ $index + 1 }}template>
- el-table-column>
-
- <el-table-column
- v-for="item in tableLabel.filter((item) => item.label)"
- :key="item[keyId]"
- :width="item.width ? item.width : ''"
- :align="!!item.align ? item.align : 'center'"
- :label="item.label"
- :show-overflow-tooltip="overflowText"
- :fixed="item.fixed"
- :prop="item.prop"
- >
- <template slot-scope="{ row }">
- <template v-if="item.Image">
- <div>
- <el-image class="table-img" :src="row.attachment" :preview-src-list="[row.attachment]">
- <template slot="error">
- <span>无span>
- template>
- el-image>
- div>
- template>
-
-
- <template v-else-if="item.progress">
- <el-progress class="progress-line" :text-inside="true" :stroke-width="26" :percentage="row[item.prop]" />
- template>
-
- <template v-else-if="item.render">
- <div style="cursor: pointer" @click="!!item.methods && handleClickon(item.methods, row)" v-html="item.render(row)" />
- 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] ? 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">
- <div
- v-if="!!option.children"
- slot-scope="{row}"
- class="flex-box"
- >
- <div
- v-for="(item, index) in option.children.filter(item => item.render ? item.render(row) : true)"
-
- :key="index"
- >
- <el-tooltip
- v-if="!item.type"
- v-permission="{ permission: item.permission }"
- class="item"
- effect="light"
- popper-class="yxp-tooltip-primary"
- :content="item.label"
- placement="top"
- >
- <i
- :class="['yxp-tooltip-icon', item.icon]"
- :plain="true"
- @click="handleTableButton(row, item.methods)"
- />
- el-tooltip>
- <el-dropdown
- v-if="item.type==='drop'"
- v-permission="{ permission: item.permission }"
- class="item"
- @command="(command) => {handleTableButton(row, command)}"
- >
- <span class="el-dropdown-link">
- <i :class="['yxp-tooltip-icon', item.icon]" />
- span>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item
- v-for="itm in item.children"
- :key="itm.methods"
- v-permission="{ permission: item.permission }"
- :command="itm.methods"
- >
- <i
- v-if="itm.icon"
- :class="['yxp-tooltip-icon', itm.icon]"
- :plain="true"
- />
- {{ itm.label }}
- el-dropdown-item>
- el-dropdown-menu>
- el-dropdown>
- div>
- div>
- el-table-column>
- el-table>
- div>
-
- <script>
- export default {
- props: {
- /**
- * 表格最高高度
- */
- maxHeight: {
- type: [String, Number],
- default: 'auto'
- },
- /**
- * 表格自定义属性展示
- */
- tableLabel: {
- type: Array,
- default: () => {
- return []
- }
- },
- /**
- * 表格数据源
- */
- data: {
- type: Array,
- default: () => {
- return []
- }
- },
- /**
- * 配置需要显示的操作菜单
- */
- option: {
- type: Object,
- default: () => {}
- },
- showCheckBox: {
- // 配置是否显示全选(复选框)
- type: Boolean,
- default: false
- },
- /**
- * 是否显示索引
- */
- showIndex: {
- type: Boolean,
- default: false
- },
- turnRadio: {
- type: Boolean,
- default: false
- },
- selectedIdArr: {
- type: Array,
- 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
- }
- },
- data() {
- return {
- curPageCheck: [],
- radioId: '',
- showVertical: false
- }
- },
- watch: {
- data: {
- handler() {
- if (this.showCheckBox || this.turnRadio) {
- this.$nextTick(() => {
- this.$refs.commonTable.clearSelection()
- this.curPageCheck = []
- if (this.showCheckBox && this.turnRadio) {
- this.data.filter((item) => {
- if (item.id === this.selectedIdArr[0]) {
- this.$refs.commonTable.toggleRowSelection(item, true)
- }
- })
- } else if (this.showCheckBox) {
- this.data.filter((item) => {
- if (this.selectedIdArr.includes(item.id)) {
- this.$refs.commonTable.toggleRowSelection(item, true)
- this.curPageCheck.push(item.id)
- }
- })
- }
- })
- }
- },
- deep: true,
- immediate: true
- },
- selectedIdArr: {
- handler(val) {
- if (this.showCheckBox || this.turnRadio) {
- this.$nextTick(() => {
- this.$refs.commonTable.clearSelection()
- this.curPageCheck = []
- if (this.showCheckBox && this.turnRadio) {
- this.data.filter((item) => {
- if (item.id === val[0]) {
- this.$refs.commonTable.toggleRowSelection(item, true)
- }
- })
- } else if (this.showCheckBox) {
- this.data.filter((item) => {
- if (val.includes(item.id)) {
- this.$refs.commonTable.toggleRowSelection(item, true)
- this.curPageCheck.push(item.id)
- }
- })
- }
- })
- }
- },
- deep: true,
- immediate: true
- }
- },
- 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) {
- this.$emit('operation', row, type);
- },
- /**
- * 后续扩展位
- * @param {*} methods
- * @param {*} row
- */
- handleClickon(methods, row) {
- this.$emit(methods, { methods, row })
- },
- handleSelectionChange(val) {
- if (this.showCheckBox && this.turnRadio) {
- // 选择项大于1时
- if (val.length > 1) {
- const del_row = val.shift()
- this.$refs.commonTable.toggleRowSelection(del_row, false)
- }
- }
- // 全选
- if (this.showCheckBox && this.selectedIdArr) {
- if (this.turnRadio) {
- this.$emit('handle-selection-change', val)
- } else {
- // 一般复选框都是走到这一步
- this.$emit('handle-selection-change', val)
- }
- } else {
- this.$emit('handle-selection-change', val)
- }
- },
- getRowKeys(row) {
- return row.id
- },
- selectAll(val) {
- if (this.showCheckBox && this.turnRadio) {
- // 选择项大于1时
- if (val.length > 1) {
- val.length = 1
- }
- }
- this.$emit('handle-selection-change', val)
- },
- // 斑马纹表格背景色
- tabRowClassName({ row, rowIndex }) {
- const index = rowIndex + 1
- if (index % 2 === 0) {
- return 'even-row'
- } else {
- return 'odd-row'
- }
- },
- cellClassName({ row, column, rowIndex, columnIndex }) {
- if (row.confirmTag === 2 && columnIndex < this.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) {
- this.$emit('rowClick', row)
- }
- }
- }
- script>
-
- <style lang="scss" scoped>
-
- ::v-deep .el-table__header,
- ::v-deep .el-table__body {
- margin: 0;
- }
-
- ::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;
- }
-
- ::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__fixed-right::before,
- .el-table__fixed::before {
- background-color: transparent;
- }
- ::v-deep .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;
- }
-
- ::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: 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;
- }
- }
- style>