对表单自由排序,决定哪些列显示隐藏,能保存设置过的操作
效果图
使用前先安装拖拽的插件,插件官网https://sortablejs.com/
npm install sortablejs --save
保留自定义表单缓存,清除其他缓存
/**
* 清除所有localStorage
*/
export function removeAll() {
//保留表单自定义的缓存项
const specialCacheKey = 'customTableCatch';
// 获取缓存的所有键
const keys = Object.keys(localStorage);
// 清除除了特定键以外的所有缓存
keys.forEach(key => {
if (key !== specialCacheKey) {
localStorage.removeItem(key);
}
});
console.log('所有的缓存',keys)
// return window.localStorage.clear();
}
使用页,操作列dataIndex要设置为action,forKey必需是唯一的
用的vue2版的antdesign vue写的样式,想用其它的ui框架可以自行修改样式
<customTable :tableHeadList="tableHead" @customTableUpde="customTableUpde" forKey="dataIndex"></customTable>
import customTable from "./components/customTable.vue" //引入
const tableHead = [
{
title: '序号',
dataIndex: 'index',
scopedSlots: { customRender: 'index' },
width: 60,
align: 'center'
},
{
title: '产品图片',
dataIndex: 'pic',
scopedSlots: { customRender: 'pic' },
ellipsis: true,
align: 'center'
},
{
title: '产品名称',
dataIndex: 'goodsName',
ellipsis: true,
align: 'center'
},
{
title: '原价',
dataIndex: 'oriPrice',
ellipsis: true,
width: 80,
align: 'center'
},
{
title: '现价',
dataIndex: 'price',
ellipsis: true,
width: 80,
align: 'center'
},
{
title: '产品分类',
dataIndex: 'goodsCategoryName',
ellipsis: true,
align: 'center'
},
{
title: '状态',
dataIndex: 'publishStatusName',
scopedSlots: { customRender: 'publishStatusName' },
ellipsis: true,
align: 'center'
},
{
title: '操作',
dataIndex:'action',
// fixed: 'right',
scopedSlots: { customRender: 'action' },
width: 140,
align: 'center'
}
];
export default {
components: { customTable },
data() {
return {
tableHeadList:[],//表单使用的头部数据
}
},
methods:{
//更新表格头部
customTableUpde(e){
this.tableHeadList = e;
},
}
customTable组件
<template>
<div>
<a-popover title="" v-model="customVisible" trigger="click" placement="topRight">
<a-icon type="setting" style="font-size:20px;" @click="waiClick" />
<template slot="content">
<div class="customBigBox">
<div :id="customId" :ref="customId" v-if="headList&&headList.length>0" class="customBox">
<div v-for="(item,index) in headList" :key="item[forKey]" >
<div class="customEach" v-if="item.dataIndex != operation">
<a-checkbox
@change="customCheckChange($event,index)"
style="width: 20px;height: 20px;margin-right:4px;"
:checked="item.ischecked"
v-model="item.ischecked"
></a-checkbox>
<div class="customText">{{item.title}}</div>
<!-- <a-tooltip placement="top" title="固定到左侧">
<a-icon type="vertical-right" class="customFixed" @click="addFixed('left',index)" :style="{'margin-left':'4px','color': (item[fixedName]&&item[fixedName]=='left')?'#1890ff':'#777'}" />
</a-tooltip>
<a-tooltip placement="top" title="固定到右侧">
<a-icon type="vertical-left" class="customFixed" @click="addFixed('right',index)" :style="{'margin-left':'10px','color': (item[fixedName]&&item[fixedName]=='right')?'#1890ff':'#777'}" />
</a-tooltip> -->
</div>
</div>
</div>
<div class="customNodata" v-else>
暂无数据
</div>
</div>
<div class="customAction">
<a-button @click="reset" style="margin-right: 16px;">重置</a-button>
<a-button type="primary" @click="save">保存</a-button>
</div>
</template>
</a-popover>
</div>
</template>
<script>
//拖拽插件,官网https://sortablejs.com/
import Sortable from 'sortablejs'
export default{
data(){
return {
customVisible:false,
headList:[],//数据
el:null,//列表元素
}
},
props:{
//组件id
customId:{
type:String,
default:'customCustomTable'
},
//指定的key字段
forKey:{
type:String,
default:'dataIndex'
},
//表头数据
tableHeadList:{
type:Array,
default:[]
},
//表头数据缓存ID,必传且每个页面传的不能相同,否则会冲突
customCacheId:{
type:String,
default:'customCustomTable'
},
//左右固定属性名
fixedName:{
type:String,
default:'fixed'
},
//操作列对应的名字
operation:{
type:String,
default:'action'
}
},
mounted(){
let data = JSON.parse(JSON.stringify(this.tableHeadList));
this.dealList(data);
this.$nextTick(() =>{
this.initDrag()
this.watchList()
})
},
methods:{
//重置
reset(){
let all = JSON.parse(window.localStorage.getItem('customTableCatch'));
console.log('重置表单',all)
//有该缓存
if(all&&all[this.customCacheId]){
all[this.customCacheId] = '';//清空原有的
window.localStorage.setItem('customTableCatch',JSON.stringify(all));//重新替换
}
let data = JSON.parse(JSON.stringify(this.tableHeadList))
this.dealList(data)
this.$message.success('重置成功')
this.customVisible = false;
},
//保存
save(){
//加个排序
this.headList.map((res,index) =>{
res.issort = index+1;
})
let all = JSON.parse(window.localStorage.getItem('customTableCatch'));
if(!all){
all = {};
}
all[this.customCacheId] = this.headList;//在对应位置加上数据
window.localStorage.setItem('customTableCatch',JSON.stringify(all));//缓存
console.log('保存',this.headList)
this.$message.success('保存成功')
this.customVisible = false;
},
//处理初始化数据
dealList(e){
const that = this;
let all = JSON.parse(window.localStorage.getItem('customTableCatch'));
let oldlist = '';
if(all&&all[this.customCacheId]){
oldlist = all[this.customCacheId];//拿取缓存数据
}
if(oldlist){
//有旧数据,新旧合并,保留旧数据的操作
let newlist = [];
console.log('拿取',oldlist)
e.map(res =>{
let resul = oldlist.filter(ve => ve[that.forKey] == res[that.forKey]);
if(resul&&resul.length>0){
let currentobj = res;
currentobj.issort = resul[0].issort;
currentobj.ischecked = resul[0].ischecked;
currentobj[that.fixedName] = resul[0][that.fixedName];
newlist.push(currentobj)
}else{
res.issort = 9999;
res.ischecked = true;
if(!res[that.fixedName]){
res[that.fixedName] = '';
}
newlist.push(res)
}
})
//排序
let sortlist = newlist.sort((a,b) =>{
let value1 = a['issort'];
let value2 = b['issort'];
return value1 - value2;
})
this.headList = sortlist;
}else{
e.map(res =>{
res.issort = 9999;
res.ischecked = true;
if(!res[that.fixedName]){
res[that.fixedName] = '';
}
})
this.headList = e;
}
this.outputData()
},
//重新初始化拖拽
waiClick(){
if(!this.el){
setTimeout(() =>{
this.$nextTick(() =>{
this.initDrag()
})
},100)
}
},
//初始化拖拽
initDrag(){
const that = this;
const el = document.getElementById(this.customId);
if(el){
this.el = el;
// 创建拖拽实例
new Sortable(el, {
group:this.customId+'group',
animation: 150,
sort: true,
onEnd: (e) => {
//拖拽回调
that.dealDragList(e.newIndex,e.oldIndex)
}
});
}
},
//监听数据变化
watchList(){
this.unwatch = this.$watch('tableHeadList',function(newlist,oldlist){
let data = JSON.parse(JSON.stringify(newlist));
this.dealList(data)
},{
deep:true //深度监听
})
},
//处理拖拽后的数据
dealDragList(newIndex,oldIndex){
if(newIndex == oldIndex)return;
let data = JSON.parse(JSON.stringify(this.headList));
const currentRow = data[oldIndex];
data.splice(oldIndex, 1);//删除原位置数据
data.splice(newIndex, 0, currentRow);
this.headList = data;
this.outputData()
},
//选择
customCheckChange(e,index){
this.headList[index].ischecked = e.target.checked;
this.outputData()
},
//固定项
addFixed(e,index){
if(e == 'left'){
if(!this.headList[index][this.fixedName] || this.headList[index][this.fixedName] == 'right'){
this.headList[index][this.fixedName] = 'left';
}else{
this.headList[index][this.fixedName] = '';
}
}else{
if(!this.headList[index][this.fixedName] || this.headList[index][this.fixedName] == 'left'){
this.headList[index][this.fixedName] = 'right';
}else{
this.headList[index][this.fixedName] = '';
}
}
this.outputData()
},
//输出数据
outputData(e){
let data = JSON.parse(JSON.stringify(this.headList));
//将符合要求的返回
let newdata = data.filter(res => res.ischecked);
this.$emit('customTableUpde',newdata)
console.log('新返回的数组',data)
},
},
beforeDestroy(){
//移除监听
if(this.unwatch){
this.unwatch()
}
}
}
</script>
<style scoped>
.customBigBox{
width:270px;
}
.customBox{
width:100%;
height: 280px;
overflow-y: scroll;
background-color: #fff;
border-radius: 6px;
padding-right: 5px;
box-sizing: border-box;
}
.customEach{
width: 100%;
height: 34px;
user-select: none;
list-style-type: none;
color: #333;
padding-left: 10px;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #fff;
}
.customText{
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.customText:hover{
color: #1890ff;
}
.customFixed{
font-size: 16px;
}
.customFixed:hover{
color: #1890ff;
}
.customAction{
width: 100%;
height: 60px;
display: flex;
justify-content: flex-end;
align-items: center;
padding: 5px 14px;
box-sizing: border-box;
}
.customNodata{
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: #999;
}
</style>