基于el-table封裝的可拖拽行列、選擇列組件的實現(xiàn)
效果

需要環(huán)境
需配置屬性

示例
<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: "狀態(tài)",
prop: "status",
width: "100",
checked: true
},
{
label: "創(chuàng)建時間",
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>
到此這篇關(guān)于基于el-table封裝的可拖拽行列、選擇列組件的實現(xiàn)的文章就介紹到這了,更多相關(guān)el-table 可拖拽行列內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!?
相關(guān)文章
vue路由跳轉(zhuǎn)攜帶參數(shù)的方式總結(jié)
我們知道在vue中每個頁面都需要在路由中聲明,下面這篇文章主要給大家介紹了關(guān)于vue路由跳轉(zhuǎn)攜帶參數(shù)的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-10-10
ElementUI Tag組件實現(xiàn)多標簽生成的方法示例
這篇文章主要介紹了ElementUI Tag組件實現(xiàn)多標簽生成的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
vue3.0 CLI - 2.2 - 組件 home.vue 的初步改造
這篇文章主要介紹了vue3.0 CLI - 2.2 - 組件 home.vue 的初步改造,home.vue 組件有了兩個屬性:navs 和 tts 屬性,具體實例代碼大家跟隨小編一起通過本文學(xué)習(xí)吧2018-09-09
lottie實現(xiàn)vue自定義loading指令及常用指令封裝詳解
這篇文章主要為大家介紹了lottie實現(xiàn)vue自定義loading指令及常用指令封裝,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09
VUE配置proxy代理的開發(fā)測試及生產(chǎn)環(huán)境
這篇文章主要為大家介紹了VUE配置proxy代理的開發(fā)環(huán)境、測試環(huán)境、生產(chǎn)環(huán)境詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08

