Vue+elementui实现列拖拽排序的组件

前言

开发管理系统时使用的框架没有拖拽表格列的功能,简单实现一个组件

现在将列拖拽的部分拆分出来,掘友们有需要的可以各自优化一下

下载相关依赖

使用了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>

总结

核心思路

  1. 子组件操作父组件的列数据来实现列的拖拽排序等各种功能
  2. 父子组件通信更新列数据
相关推荐
hakesashou几秒前
python交互式命令时如何清除
java·前端·python
HEX9CF19 分钟前
【CTF Web】Pikachu xss之href输出 Writeup(GET请求+反射型XSS+javascript:伪协议绕过)
开发语言·前端·javascript·安全·网络安全·ecmascript·xss
凌云行者31 分钟前
使用rust写一个Web服务器——单线程版本
服务器·前端·rust
华农第一蒟蒻1 小时前
Java中JWT(JSON Web Token)的运用
java·前端·spring boot·json·token
积水成江1 小时前
关于Generator,async 和 await的介绍
前端·javascript·vue.js
___Dream1 小时前
【黑马软件测试三】web功能测试、抓包
前端·功能测试
金灰1 小时前
CSS3练习--电商web
前端·css·css3
人生の三重奏1 小时前
前端——js补充
开发语言·前端·javascript
Tandy12356_1 小时前
js逆向——webpack实战案例(一)
前端·javascript·安全·webpack
TonyH20021 小时前
webpack 4 的 30 个步骤构建 react 开发环境
前端·css·react.js·webpack·postcss·打包