【fix 66426】完成JTable的隐藏冻结列控制
This commit is contained in:
@@ -0,0 +1,299 @@
|
|||||||
|
<template>
|
||||||
|
<a-table
|
||||||
|
ref='table'
|
||||||
|
:table-key="tableKey"
|
||||||
|
:columns="resultColumns"
|
||||||
|
v-bind="$attrs"
|
||||||
|
v-on="$listeners">
|
||||||
|
|
||||||
|
<template v-for="(slotItem) of slots" :slot="slotItem" slot-scope="text, record, index">
|
||||||
|
<slot :name="slotItem" v-bind="{text,record,index}"></slot>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div slot="settingDropdown">
|
||||||
|
<a-card>
|
||||||
|
<!-- scroll.x 要大于表格所有固定列宽的合,每个列都要有width,否则定位后宽度会出现变形,否则会出现问题 -->
|
||||||
|
<a-table
|
||||||
|
rowKey="key"
|
||||||
|
:style="settingStyle"
|
||||||
|
tableLayout="fixed"
|
||||||
|
size="small"
|
||||||
|
bordered
|
||||||
|
:pagination="false"
|
||||||
|
:scroll="settingScroll"
|
||||||
|
:data-source="settingDataSource"
|
||||||
|
:columns="settingColumns">
|
||||||
|
|
||||||
|
<a-checkbox slot="hide" slot-scope="text, record"
|
||||||
|
:checked="text"
|
||||||
|
:disabled="record.disabledHide"
|
||||||
|
@change="changeSetting(text, 'hide', record)"></a-checkbox>
|
||||||
|
<a-checkbox slot="freeze" slot-scope="text, record"
|
||||||
|
:checked="text"
|
||||||
|
:disabled="record.disabledFreeze"
|
||||||
|
@change="changeSetting(text, 'freeze', record)"></a-checkbox>
|
||||||
|
</a-table>
|
||||||
|
</a-card>
|
||||||
|
</div>
|
||||||
|
<a-icon ref='settingBtn' slot="settingIcon" type='setting' :style="{ fontSize:'16px', color: '#108ee9' }" />
|
||||||
|
|
||||||
|
</a-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Vue from 'vue'
|
||||||
|
import { cloneDeep } from 'lodash'
|
||||||
|
|
||||||
|
// 操作列的key或dataIndex
|
||||||
|
const actionKey = 'action'
|
||||||
|
// 保存localStorage中的后缀
|
||||||
|
const saveSuffix = ':JTable'
|
||||||
|
// 拿到column的key
|
||||||
|
const getKey = col => col.key || col.dataIndex
|
||||||
|
// 所有JTable的缓存key
|
||||||
|
const J_TABLE_KEYS = 'J_TABLE_KEYS'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 以下 表格为实际要展示的表、配置表为设置冻结和隐藏的表
|
||||||
|
* 执行流程梳理
|
||||||
|
* 1.mounted挂载时去拿配置
|
||||||
|
* 1.1.从localStorage取历史配置:取到直接进入2 没取到就进1.2
|
||||||
|
* 1.2.从父组件获取columns初始化配置 并存储到localStorage
|
||||||
|
*
|
||||||
|
* 2.拿到配置后
|
||||||
|
* 2.1.watch进行监听配置,然后生成 配置表格的数据,再调用setResultColumns来更新表格
|
||||||
|
* 2.2.将columns根据配置转换成resultColumns进行渲染表格
|
||||||
|
*
|
||||||
|
* 3.修改配置触发changeSetting来对配置进行更新,更新后watch会监听到跳转2如此循环
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JTable',
|
||||||
|
props: {
|
||||||
|
tableKey: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
// 配置表的样式
|
||||||
|
settingStyle: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: () => ({ width: '300px' })
|
||||||
|
},
|
||||||
|
// 配置表的scroll
|
||||||
|
settingScroll: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: () => ({ y: 300 })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
// 设置表格
|
||||||
|
settingColumns: [
|
||||||
|
{ title: '列名', dataIndex: 'title', align: 'center', ellipsis: true, width: 150 },
|
||||||
|
{ title: '隐藏', dataIndex: 'hide', align: 'center', ellipsis: true, width: 60, scopedSlots: { customRender: 'hide' } },
|
||||||
|
{ title: '冻结', dataIndex: 'freeze', align: 'center', ellipsis: true, width: 60, scopedSlots: { customRender: 'freeze' } }
|
||||||
|
],
|
||||||
|
settingDataSource: [],
|
||||||
|
settingColumnsObj: { hide: [], freeze: [] }, // 本地存储的配置对象
|
||||||
|
resultColumns: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
slots () {
|
||||||
|
const slots = []
|
||||||
|
for (const column of this.columns) {
|
||||||
|
if (column.scopedSlots && column.scopedSlots.customRender) {
|
||||||
|
slots.push(column.scopedSlots.customRender)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slots
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// 配置列改变,将配置转换成配置表格数据
|
||||||
|
settingColumnsObj: {
|
||||||
|
deep: true, // 深度监听
|
||||||
|
immediate: true, // 挂载先执行一次
|
||||||
|
handler () {
|
||||||
|
const dataSource = []
|
||||||
|
this.columns.forEach(col => {
|
||||||
|
const tempKey = getKey(col)
|
||||||
|
// 操作栏不可配置
|
||||||
|
if (tempKey === actionKey) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// hideSettingColumn: true 可以让不显示字段控制
|
||||||
|
if (col.hideSettingColumn) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dataSource.push({
|
||||||
|
title: col.title, // 用于显示的字段
|
||||||
|
key: tempKey, // 用于存储的字段
|
||||||
|
hide: this.settingColumnsObj.hide.includes(tempKey), // 是否隐藏
|
||||||
|
freeze: this.settingColumnsObj.freeze.includes(tempKey), // 是否冻结
|
||||||
|
disabledHide: col.disabledHide, // 禁用隐藏
|
||||||
|
disabledFreeze: col.disabledFreeze // 禁用冻结
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.settingDataSource = dataSource
|
||||||
|
this.setResultColumns()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* 将父组件的columns进行处理:增加设置列按钮
|
||||||
|
* 冻结列要有width,否则会有问题,建议使用minWidth,scroll.x要大于所有列width的和
|
||||||
|
*/
|
||||||
|
setResultColumns () {
|
||||||
|
// 深度克隆,防止直接修改父组件数据
|
||||||
|
const columns = cloneDeep(this.columns)
|
||||||
|
// 设置按钮插槽配置
|
||||||
|
const settingOption = {
|
||||||
|
scopedSlots: {
|
||||||
|
filterDropdown: 'settingDropdown',
|
||||||
|
filterIcon: 'settingIcon',
|
||||||
|
customRender: 'action'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const findActionIndex = columns.findIndex(col => col && (getKey(col) === actionKey))
|
||||||
|
// 如果找到操作栏,就把设置加到操作栏上
|
||||||
|
if (findActionIndex !== -1) {
|
||||||
|
// 添加设置插槽配置,并固定右侧
|
||||||
|
Object.assign(columns[findActionIndex], settingOption, { fixed: 'right' })
|
||||||
|
} else {
|
||||||
|
// 如果没有找到操作栏,就把最后列加上设置插槽配置
|
||||||
|
Object.assign(columns[columns.length - 1], settingOption)
|
||||||
|
}
|
||||||
|
// 最后过滤掉需要隐藏的字段,按定位进行排序
|
||||||
|
const startArr = [] // 冻结左侧的列
|
||||||
|
const midArr = [] // 没有冻结的列
|
||||||
|
const endArr = [] // 冻结右侧的列(只能是action,暂时不能自定义固定右侧)
|
||||||
|
columns.forEach(col => {
|
||||||
|
const key = getKey(col)
|
||||||
|
const fixed = this.settingColumnsObj.freeze.includes(key)
|
||||||
|
col.hide = this.settingColumnsObj.hide.includes(key)
|
||||||
|
col.fixed = key === actionKey ? 'right' : fixed
|
||||||
|
if (!col.hide) {
|
||||||
|
// 如果没有宽度就取minWidth(不添加原数据的width属性,这里只对需要固定的minWidth生效)
|
||||||
|
const minWidth = col.width || col.minWidth
|
||||||
|
switch (col.fixed) {
|
||||||
|
case true:
|
||||||
|
case 'left':
|
||||||
|
startArr.push({ ...col, width: minWidth })
|
||||||
|
break
|
||||||
|
case 'right':
|
||||||
|
endArr.push({ ...col, width: minWidth })
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
midArr.push(col)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 更新父组件的数据,将排序后的进行渲染
|
||||||
|
this.$emit('update:columns', columns)
|
||||||
|
this.resultColumns = [...startArr, ...midArr, ...endArr]
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 配置表中复选框改变状态的事件
|
||||||
|
* @param text 修改前的状态
|
||||||
|
* @param type 隐藏还是冻结
|
||||||
|
* @param record 当前行数据
|
||||||
|
*/
|
||||||
|
changeSetting (text, type, record) {
|
||||||
|
const checked = !text // text是点击前的状态,取反就是要修改的状态
|
||||||
|
console.log('修改了配置', checked, type, record)
|
||||||
|
// 修改当前行配置
|
||||||
|
record[type] = !checked
|
||||||
|
// 勾选就添加,取消就删除
|
||||||
|
if (checked) {
|
||||||
|
this.settingColumnsObj[type].push(record.key)
|
||||||
|
} else {
|
||||||
|
this.settingColumnsObj[type].splice(this.settingColumnsObj[type].findIndex(item => item === record.key), 1)
|
||||||
|
}
|
||||||
|
this.saveSetting()
|
||||||
|
/**
|
||||||
|
* 弹框消失问题 冻结列会导致dom结构改变而从局部更新丢失弹框
|
||||||
|
* 情况1:原本显示没有冻结列,新增第一个冻结列
|
||||||
|
* 情况2:原本有且只剩一个冻结列,取消最后一个冻结列
|
||||||
|
* 解决方案,刷新前获取dom,刷新后再次获取,如果获取不一致就触发点击事件点开弹框
|
||||||
|
*/
|
||||||
|
const beforeIsFixed = !!this.$refs.table.$el.querySelector('.ant-table-fixed-left')
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const afterIsFixed = !!this.$refs.table.$el.querySelector('.ant-table-fixed-left')
|
||||||
|
// console.log(beforeIsFixed, afterIsFixed)
|
||||||
|
if (beforeIsFixed !== afterIsFixed) {
|
||||||
|
this.$refs.settingBtn.$el.click()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 初始化配置,从columns里获取
|
||||||
|
initSetting () {
|
||||||
|
const hide = []
|
||||||
|
const freeze = []
|
||||||
|
this.columns.forEach(col => {
|
||||||
|
const key = getKey(col)
|
||||||
|
// hide属性控制隐藏
|
||||||
|
if (col.hide) {
|
||||||
|
hide.push(key)
|
||||||
|
}
|
||||||
|
// fixed冻结到左侧
|
||||||
|
if (col.fixed === true || col.fixed === 'left') {
|
||||||
|
freeze.push(key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.settingColumnsObj = { hide, freeze }
|
||||||
|
this.saveSetting()
|
||||||
|
},
|
||||||
|
// 配置保存到本地
|
||||||
|
saveSetting () {
|
||||||
|
// 获取所有的jtable缓存的key数组(用于清除缓存,没有就初始化数组)
|
||||||
|
const jTableKeys = Vue.ls.get(J_TABLE_KEYS) || []
|
||||||
|
const saveKey = this.tableKey + saveSuffix
|
||||||
|
// 如果不在数组里面就追加进去
|
||||||
|
if (!jTableKeys.includes(saveKey)) {
|
||||||
|
jTableKeys.push(saveKey)
|
||||||
|
}
|
||||||
|
Vue.ls.set(J_TABLE_KEYS, jTableKeys, 7 * 24 * 60 * 60 * 10)
|
||||||
|
Vue.ls.set(saveKey, this.settingColumnsObj, 7 * 24 * 60 * 60 * 10)
|
||||||
|
},
|
||||||
|
// 清除本地的配置(当前的JTable)
|
||||||
|
clearSetting () {
|
||||||
|
this.settingColumnsObj = { hide: [], freeze: [] }
|
||||||
|
Vue.ls.remove(this.tableKey + saveSuffix)
|
||||||
|
this.$message.success('成功清除当前JTable的缓存!')
|
||||||
|
},
|
||||||
|
// 清除所有缓存
|
||||||
|
clearAllCacheSetting () {
|
||||||
|
// 获取到之后遍历删除,最后把keys数组删除
|
||||||
|
const jTableKeys = Vue.ls.get(J_TABLE_KEYS)
|
||||||
|
jTableKeys && jTableKeys.forEach(key => {
|
||||||
|
Vue.ls.remove(key)
|
||||||
|
})
|
||||||
|
Vue.ls.remove(J_TABLE_KEYS)
|
||||||
|
this.$message.success('成功清除全局JTable的缓存!')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
const settingColumnsObj = Vue.ls.get(this.tableKey + saveSuffix)
|
||||||
|
// 第一次进页面或清空缓存进行初始化
|
||||||
|
if (settingColumnsObj) {
|
||||||
|
this.settingColumnsObj = settingColumnsObj
|
||||||
|
} else {
|
||||||
|
this.initSetting()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang='less' scoped>
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user