問題描述
在開發(fā)中遇到一個需求,即實現(xiàn)table列的拖拽,但是調(diào)研發(fā)現(xiàn),大部分是基于sorttable.js這個包實現(xiàn)的,但是通過實際應(yīng)用,發(fā)現(xiàn)sorttable.js用在操作element table 組件中并不是很舒服,總會莫名其妙的冒出一些異常bug,于是自行封裝一個table 列拖拽組件。
難點概括
①element table header插槽應(yīng)用
②drag知識點應(yīng)用
③splice()方法理解
演示代碼
<template>
<div>
<h1>基于element-ui table列拖拽實現(xiàn)</h1>
<drag-head :head-columns="tableHead" :data="tableData"></drag-head>
</div>
</template>
<script>
import DragHead from "./dragHead.vue";
export default {
name: "DragHeadCase",
components: { DragHead },
data() {
return {
tableHead: [
{
label: "零零",
prop: "v0",
width: 150,
},
{
label: "一一",
prop: "v1",
width: 150,
},
{
label: "二二",
prop: "v2",
width: 150,
},
{
label: "三三",
prop: "v3",
width: 150,
},
{
label: "四四",
prop: "v4",
width: 300,
},
{
label: "五五",
prop: "v5",
},
{
label: "六六",
prop: "v6",
},
{
label: "七七",
prop: "v7",
},
{
label: "八八",
prop: "v8",
},
{
label: "九九",
prop: "v9",
},
],
tableData: [
{
v0: "2016-05-02",
v1: "王小虎",
v2: "上海",
v3: "普陀區(qū)",
v4: "上海市普陀區(qū)金沙江路 1518 弄",
v5: 200333,
v6: "2016-05-02",
v7: "王小虎",
v8: "上海",
v9: "普陀區(qū)",
},
{
v0: "2016-05-02",
v1: "王小虎",
v2: "上海",
v3: "普陀區(qū)",
v4: "上海市普陀區(qū)金沙江路 1518 弄",
v5: 200333,
v6: "2016-05-02",
v7: "王小虎",
v8: "上海",
v9: "普陀區(qū)",
},
{
v0: "2016-05-02",
v1: "王小虎",
v2: "上海",
v3: "普陀區(qū)",
v4: "上海市普陀區(qū)金沙江路 1518 弄",
v5: 200333,
v6: "2016-05-02",
v7: "王小虎",
v8: "上海",
v9: "普陀區(qū)",
},
{
v0: "2016-05-02",
v1: "王小虎",
v2: "上海",
v3: "普陀區(qū)",
v4: "上海市普陀區(qū)金沙江路 1518 弄",
v5: 200333,
v6: "2016-05-02",
v7: "王小虎",
v8: "上海",
v9: "普陀區(qū)",
},
{
v0: "2016-05-02",
v1: "王小虎",
v2: "上海",
v3: "普陀區(qū)",
v4: "上海市普陀區(qū)金沙江路 1518 弄",
v5: 200333,
v6: "2016-05-02",
v7: "王小虎",
v8: "上海",
v9: "普陀區(qū)",
},
],
};
},
};
</script>
table 列 拖拽組件實現(xiàn)代碼
<template>
<div style="width: 1000px">
<el-table
ref="elTable"
border
style="width: 100%"
v-bind="$attrs"
v-on="$listeners"
:key="headKey"
:cell-class-name="cellClassName"
:header-cell-class-name="cellClassName"
>
<!-- 循環(huán)表頭 -->
<template v-for="(col, index) in tableHead">
<el-table-column
:key="index"
:prop="col.prop"
:align="col.align || 'center'"
:width="col.width || 100"
>
<!-- 通過插槽為表頭綁定mousedown和dragover方法 -->
<template slot="header" slot-scope="{ column, $index }">
<span
@mousedown="handleMounseDown($event, column, $index)"
@dragover="handleDragover($event, column, $index)"
>
{{ col.label }}
</span>
</template>
</el-table-column>
</template>
</el-table>
</div>
</template>
<script>
export default {
props: {
headColumns: Array,
},
mounted() {
/** 備用操作(如果需要對headColumns數(shù)組操作) */
this.tableHead = this.headColumns;
},
data() {
return {
tableHead: [],
// 拖拽狀態(tài)
dragState: {
start: -3, // 起始元素的 index 防止初始化cellStyle時序號、展開等默認樣式改變,最好小于-3
end: -3, // 移動鼠標時所覆蓋的元素 index
dragging: false, // 是否正在拖動
direction: undefined, // 拖動方向
},
headKey: "dragHead", // 表頭數(shù)組變換位置時,重繪table(不更新該值,表頭數(shù)組變化時,頁面不會改變)
scrollX: 0, // 初始x軸scroll位置(用于定位X軸滾動條)
};
},
methods: {
/** 鼠標摁下觸發(fā) */
handleMounseDown(e, column, $index) {
this.dragState.dragging = true;
this.dragState.start = parseInt($index - 0);
// 添加鼠標抬起事件 消除鼠標摁下立刻松開問題
document.addEventListener("mouseup", this.handleMouseUp);
// 添加拖拽結(jié)束事件
document.addEventListener("dragend", this.handleMouseUp);
// 對選中的表頭允許其拖拽
const dragclass = ".el-table__header-wrapper ." + column.id;
const dragDom = document.querySelectorAll(dragclass);
dragDom.forEach((dom) => {
// 允許表頭塊可以被拖拽 draggable 屬性 不允許拖拽dragover等相關(guān)拖拽事件無法觸發(fā)
dom.setAttribute("draggable", true);
});
},
/** 鼠標在拖拽移動時觸發(fā) */
handleDragover(e, column, $index) {
if (this.dragState.dragging) {
// 獲取當前滾動條的位置
const scrollDom = this.$refs.elTable.bodyWrapper;
this.scrollX = scrollDom.scrollLeft;
const index = parseInt($index - 0); // 記錄起始列
/** 實時更改鼠標處于表頭的位置 */
if (index - this.dragState.start !== 0) {
this.dragState.direction =
index - this.dragState.start < 0 ? "left" : "right"; // 判斷拖動方向
this.dragState.end = parseInt($index - 0);
} else {
this.dragState.end = this.dragState.start;
this.dragState.direction = null;
}
}
},
/** 鼠標抬起或拖拽結(jié)束觸發(fā) */
handleMouseUp() {
// 更新拖拽后的表頭
this.headDraged(this.dragState);
const { end } = this.dragState;
// 初始化拖動狀態(tài)
this.dragState = {
start: end, //記錄最后拖動的位置
end: -9,
dragging: false,
direction: undefined,
};
document.removeEventListener("mouseup", this.handleMouseUp);
document.removeEventListener("dragend", this.handleMouseUp);
setTimeout(() => {
// 重置拖拽狀態(tài)
this.dragState.start = -9;
}, 500);
},
// 更新拖拽后的表頭
headDraged({ start, end, direction }) {
if (direction) {
const originColumn = this.tableHead[start];
// 有位置交換時,原先位置的元素刪除,再在目標處插入
this.tableHead.splice(start, 1);
this.tableHead.splice(end, 0, originColumn);
this.headKey = new Date().getTime() + ""; // 更新table key值
this.$nextTick(() => {
// 因為表頭重繪后滾動條會移到最左端初始位置,因此如果是在中間部分拖拽,還需要把滾動條在定位到該位置
this.$refs.elTable.bodyWrapper.scrollLeft = this.scrollX;
});
}
},
// 拖動虛線樣式設(shè)置
cellClassName({ columnIndex }) {
const { start, end, direction } = this.dragState;
const target = columnIndex - 0;
if (target === start) {
// 被移動的元素
return "drag_start";
} else if (target === end) {
// 要移動的位置
return `drag_end_${direction}`;
}
return "";
},
},
};
</script>
<style lang="scss" scoped>
::v-deep .el-table {
.drag_start {
opacity: 0.8;
background-color: rgba(0, 0, 0, 0.938);
color: #f3e8e8fd;
transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
}
.drag_end_left {
border-left: 2px dotted rgba(0, 0, 0, 0.938);
}
.drag_end_right {
border-right: 2px dotted rgba(0, 0, 0, 0.938);
}
}
</style>
然后我在操作的時候碰到一個報錯
[Violation ] Added non-passive event listener to ascroll- blocking 'mousewheel’event Consider marking event handler as ’ passive’to make the page more responsive. See https: com/feature/574554 3795965952
翻譯:
[沖突]在ascroll中添加了非被動事件偵聽器-阻塞“mousewheel”事件考慮將事件處理程序標記為“passive”,以使頁面更具響應(yīng)性。參見https:com/feature/574554 3795965952
解決辦法:
npm i default-passive-events -S main.js import 'default-passive-events'
最后
該組件目前僅支持最簡單的拖拽效果,后續(xù)開發(fā)出兼容fixed、checkbox、expand 以及操作列的組件會及時更新文章,有興趣的朋友可以點贊收藏。
參考文獻
基于element UI 實現(xiàn) table 列 拖拽_element table列拖拽_淡然自若_blog的博客-CSDN博客文章來源:http://www.zghlxwxcb.cn/news/detail-670786.html
Added non-passive event listener to ascroll- blocking ‘mousewheel‘event Consider marking event handl_紳士的可怖的博客-CSDN博客文章來源地址http://www.zghlxwxcb.cn/news/detail-670786.html
到了這里,關(guān)于基于element UI 實現(xiàn) table 列 拖拽的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!