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. 父子组件通信更新列数据
相关推荐
gqkmiss16 分钟前
Chrome 浏览器 131 版本开发者工具(DevTools)更新内容
前端·chrome·浏览器·chrome devtools
Summer不秃22 分钟前
Flutter之使用mqtt进行连接和信息传输的使用案例
前端·flutter
旭日猎鹰26 分钟前
Flutter踩坑记录(二)-- GestureDetector+Expanded点击无效果
前端·javascript·flutter
Viktor_Ye32 分钟前
高效集成易快报与金蝶应付单的方案
java·前端·数据库
hummhumm34 分钟前
第 25 章 - Golang 项目结构
java·开发语言·前端·后端·python·elasticsearch·golang
乐闻x1 小时前
Vue.js 性能优化指南:掌握 keep-alive 的使用技巧
前端·vue.js·性能优化
一条晒干的咸魚1 小时前
【Web前端】创建我的第一个 Web 表单
服务器·前端·javascript·json·对象·表单
Amd7941 小时前
Nuxt.js 应用中的 webpack:compiled 事件钩子
前端·webpack·开发·编译·nuxt.js·事件·钩子
生椰拿铁You1 小时前
09 —— Webpack搭建开发环境
前端·webpack·node.js
狸克先生2 小时前
如何用AI写小说(二):Gradio 超简单的网页前端交互
前端·人工智能·chatgpt·交互