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. 父子组件通信更新列数据
相关推荐
程序员爱技术1 小时前
Vue 2 + JavaScript + vue-count-to 集成案例
前端·javascript·vue.js
并不会2 小时前
常见 CSS 选择器用法
前端·css·学习·html·前端开发·css选择器
衣乌安、2 小时前
【CSS】居中样式
前端·css·css3
兔老大的胡萝卜2 小时前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
低代码布道师2 小时前
CSS的三个重点
前端·css
耶啵奶膘3 小时前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^5 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie5 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic6 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿6 小时前
webWorker基本用法
前端·javascript·vue.js