前言
开发管理系统时使用的框架没有拖拽表格列的功能,简单实现一个组件
现在将列拖拽的部分拆分出来,掘友们有需要的可以各自优化一下
下载相关依赖
使用了elementui,拖拽使用了vuedraggable可以自行更换
js
npm install element-ui
npm install vuedraggable
实现原理
- 调用拖拽api实现拖拽的效果,本文使用了vuedraggable插件
- 将拖拽的列传递给子组件显示利用拖拽api拖拽
- 通过拖拽列名顺序替换列数据的顺序同时更新key值
- 父组件接收子组件更新的数据赋值给父组件的列数据
展示效果
上代码
父组件
父组件向子组件传递要拖拽的表格列columns 以及编写更新父组件数据的方法handleColumns
js
<template>
<div style="padding: 50px;">
<columndrag :columns="columns" @update:columns="handleColumns"></columndrag>
<el-table ref="ordertable" :data="tableData" style="margin: 20px;">
<template v-for="column in columns">
<el-table-column :key="column.key" :prop="column.prop" :label="column.label" v-if="column.visible">
</el-table-column>
</template>
</el-table>
</div>
</template>
<script>
import columndrag from "../components/columnsDrag";
export default {
components: { columndrag },
data() {
return {
tableData: [
{ name: '张三', age: 18, gender: '男', constellation: '水瓶', hobby: '打篮球' },
{ name: '李四', age: 20, gender: '女', constellation: '水瓶', hobby: '打篮球' },
{ name: '王五', age: 22, gender: '男', constellation: '水瓶', hobby: '打篮球' }
],
columns: [
{ key:'0',prop: 'name', label: '姓名', visible: true },
{ key:'1',prop: 'age', label: '年龄', visible: true },
{ key:'2',prop: 'gender', label: '性别', visible: true },
{ key:'3',prop: 'constellation', label: '星座', visible: true },
{ key:'4',prop: 'hobby', label: '爱好', visible: true }
]
};
},
methods: {
handleColumns(param) {
this.columns = param
this.$nextTick(() => {
this.$refs.ordertable.doLayout();
});
},
},
};
</script>
columnsDrag
js
<template>
<div>
<el-tooltip effect="dark" content="列设置" placement="top" v-if="columns != undefined">
<el-dropdown trigger="click" :hide-on-click="false" style="padding-left: 12px">
<el-button size="mini" circle icon="el-icon-menu" />
<el-dropdown-menu slot="dropdown" class="dropDownbox">
<draggable @change="handleDragEnd()" animation="300" v-model.sync="propColumns">
<el-dropdown-item v-for="column in propColumns" :key="column.label">
<el-checkbox v-model="column.visible"
@change="monitorChange($event, column.label)" :label="column.label"></el-checkbox>
</el-dropdown-item>
</draggable>
</el-dropdown-menu>
</el-dropdown>
</el-tooltip>
</div>
</template>
<script>
import draggable from 'vuedraggable';
export default {
components: { draggable },
name: "columnsDrag",
data() {
return {
propColumns: []
};
},
props: {
columns: {
type: Array,
},
},
emit: ['update:columns'],
created() {
this.propColumns = this.deepClone(this.columns, [])
},
mounted() {
},
methods: {
// 递归深克隆
deepClone(obj, newObj) {
var newObj = newObj || {};
for (let key in obj) {
if (typeof obj[key] == 'object') {
newObj[key] = (obj[key].constructor === Array) ? [] : {}
this.deepClone(obj[key], newObj[key]);
} else {
newObj[key] = obj[key]
}
}
return newObj;
},
handleDragEnd() {
for (let i = 0; i < this.propColumns.length; i++) {
this.propColumns[i].key = new Date().getTime() + i
}
// 触发事件让父组件更新columns
this.$emit('update:columns', this.propColumns)
},
// 显隐列操作
monitorChange(event, label) {
this.propColumns.filter(column => column.label == label)[0].visible = event
this.$emit('update:columns', this.propColumns)
},
},
};
</script>
<style>
.dropDownbox {
width: 200px;
max-height: 450px;
overflow-y: auto;
overflow-x: hidden;
}
</style>
总结
核心思路
- 子组件操作父组件的列数据来实现列的拖拽排序等各种功能
- 父子组件通信更新列数据