效果
需要环境
vue
elementUI
拖拽插件Sortable.js
需配置属性
示例
<HTable
:columns="columns"
:data="list"
:setColumn="true"
tableKey="CategoriesList"
style="width: 100%"
border
>
// 这里可以放插槽
<template slot="create_time" slot-scope="scope">
{{ scope.column.label + scope.item.prop }}
</template>
<template slot="action" slot-scope="scope">
<el-button type="primary" @click="handleEdit(scope.row)" size="small">
编辑
</el-button>
<el-button @click="handleDelete(scope.row)" type="danger" size="small">
删除
</el-button>
</template>
</HTable>
import HTable from "@/components/HTable";
export default {
components: { HTable },
data() {
return {
list: [],
columns: [
{
label: "ID", // 描述
prop: "_id", // 列的唯一值。 必须要有
checked: true // 是否展示该列
... // 一些el-table-column的属性都可以写在这里
},
{
label: "分类名称",
prop: "name",
checked: true
},
{
label: "上级分类",
prop: "parent.name",
checked: true
},
{
label: "状态",
prop: "status",
width: "100",
checked: true
},
{
label: "创建时间",
prop: "create_time",
slotHeaderName: "create_time", // 自定义表头
checked: true
},
{
label: "操作",
prop: "action",
fixed: "right",
"min-width": "100",
slotName: "action", // 自定义单元格插槽
checked: true,
disabled: true
}
]
};
}
};
有用到的话给我点个赞!附组件代码
<template>
<div class="HTable">
<div class="settingBox" v-if="setColumn">
<el-popover
placement="bottom-end"
trigger="click"
popper-class="settingPopper"
>
<el-checkbox-group
v-model="selectCol"
@change="handleChangeSelectColumn"
>
<el-checkbox
v-for="item in col"
:key="item.prop"
:label="item.prop"
:disabled="item.disabled"
style="display:block;line-height:2;margin-right:0;"
>{{ item.label }}</el-checkbox
>
</el-checkbox-group>
<i class="icon el-icon-setting" slot="reference"></i>
</el-popover>
</div>
<el-table
v-bind="$attrs"
:data="tableData"
v-on="$listeners"
:key="JSON.stringify(checkedCol)"
>
<el-table-column
v-for="(item, index) in checkedCol"
:key="item.prop"
v-bind="item"
:index="index"
:column-key="item.prop"
>
<template v-if="item.slotHeaderName" v-slot:header="scope">
<slot :name="item.slotHeaderName" v-bind="scope" :item="item"></slot>
</template>
<template v-if="item.slotName" v-slot:default="scope">
<slot :name="item.slotName" v-bind="scope"></slot>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import Sortable from "sortablejs";
export default {
name: "HTable",
props: {
tableKey: String,
columns: {
type: Array,
default() {
return [];
}
},
data: {
type: Array,
default() {
return [];
}
},
setColumn: {
type: Boolean,
default: false
}
},
watch: {
columns: {
handler(newVal) {
let localVal = this.getStorageCol();
let hotVal = [];
if (localVal) {
hotVal = this.dataDiff(newVal, localVal);
} else {
hotVal = [...newVal];
}
this.col = hotVal.map(
(item, index) =>
(item = { ...item, index, checked: item.checked || false })
);
this.checkedCol = this.checkedColFun(this.col);
this.selectCol = this.checkedCol.map(item => (item = item.prop));
},
immediate: true
},
data: {
handler(newVal) {
this.tableData = [...newVal];
},
immediate: true
},
col: {
handler(newVal) {
this.setStorageCol(newVal);
},
deep: true,
immediate: true
}
},
data() {
return {
tableData: [],
col: [],
checkedCol: [],
selectCol: []
};
},
mounted() {
document.body.ondrop = function(event) {
event.preventDefault();
event.stopPropagation();
};
this.$nextTick(() => {
this.rowDrop();
this.columnDrop();
});
},
methods: {
drap() {
this.$nextTick(() => {
this.rowDrop();
this.columnDrop();
});
},
handleChangeSelectColumn() {
this.col.forEach(item => {
if (this.selectCol.includes(item.prop)) {
item.checked = true;
} else {
item.checked = false;
}
});
this.checkedCol = this.checkedColFun(this.col);
this.drap();
},
rowDrop() {
const tbody = document.querySelector(".el-table__body-wrapper tbody");
Sortable.create(tbody, {
onEnd: ({ newIndex, oldIndex }) => {
[this.tableData[newIndex], this.tableData[oldIndex]] = [
this.tableData[oldIndex],
this.tableData[newIndex]
];
this.drap();
this.$emit("dropRow", {
drapRow: this.tableData[oldIndex],
targetRow: this.tableData[newIndex],
drapRowIndex: oldIndex,
targetRowIndex: newIndex,
data: this.tableData
});
}
});
},
columnDrop() {
const wrapperTr = document.querySelector(".el-table__header-wrapper tr");
Sortable.create(wrapperTr, {
animation: 180,
delay: 0,
onEnd: ({ newIndex, oldIndex }) => {
const oldItem = this.checkedCol[oldIndex];
const newItem = this.checkedCol[newIndex];
[this.col[newItem.index].index, this.col[oldItem.index].index] = [
oldItem.index,
newItem.index
];
this.col.sort((a, b) => {
return a.index - b.index;
});
this.checkedCol = this.checkedColFun(this.col);
this.tableData = this.tableData.slice(0, this.tableData.length);
this.drap();
this.$emit("dropCol", {
colItem: oldItem,
newIndex: newIndex,
oldIndex: oldIndex,
column: this.checkedCol
});
}
});
},
checkedColFun(arr) {
return arr.filter(item => item.checked);
},
setStorageCol(data) {
if (this.tableKey && data && data.length > 0) {
localStorage.setItem("HTable-" + this.tableKey, JSON.stringify(data));
}
},
getStorageCol() {
let datajson = localStorage.getItem("HTable-" + this.tableKey);
return datajson ? JSON.parse(datajson) : "";
},
dataDiff(newVal, localVal) {
let nl = newVal.length;
let ll = localVal.length;
if (nl != ll) {
return newVal;
} else {
let np = newVal.map(item => item.prop).sort();
let lp = localVal.map(item => item.prop).sort();
if (np.join() != lp.join()) {
return newVal;
} else {
let nnl = [];
for (let i = 0; i < localVal.length; i++) {
const item_l = localVal[i];
for (let j = 0; j < newVal.length; j++) {
const item_n = newVal[j];
if (item_l.prop === item_n.prop) {
nnl.push({
...item_n,
index: item_l.index
});
}
}
}
return nnl;
}
}
}
}
};
</script>
<style lang="less" scoped>
.HTable {
position: relative;
.settingBox {
width: 36px;
height: 36px;
border-radius: 2px;
border: 1px solid #ebeef5;
border-bottom: 0;
margin-left: auto;
position: relative;
.icon {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 36px;
height: 36px;
text-align: center;
font-size: 20px;
line-height: 36px;
color: #909399;
cursor: pointer;
}
}
}
</style>
<style lang="less">
.settingPopper {
min-width: 100px !important;
}
</style>
到此这篇关于基于el-table封装的可拖拽行列、选择列组件的实现的文章就介绍到这了,更多相关el-table 可拖拽行列内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界! |
请发表评论