拖拽式字段排序实践记录(基于vuedraggable)

前言

本文记录了如何引入vuedraggable以完成属性项的拖拽式操作,并将拖拽的排列顺序记录入表。

需求说明

项目中存在一种宽表展示的功能,其基本逻辑为:由管理员配置宽表需要展示的字段、字段的数据源之后,用户可以在展示页查看到对应的表格数据。
宽表配置端示例
宽表展示端示例
现对宽表可配置项提出新需求,要求可以自由配置的字段的展示顺序

需求分析

实现方案1:字段行可拖拽

这种实现方案是基于现存的字段配置组件,增加可拖拽的效果,如下图:
垂直列表拖拽演示
因为待选字段可能很多(几十个),而且只有勾选了的字段才需要展示、才需要参加排序,所以使用这这拖拽方式会使字段排序操作很费劲。

实现方案2:新增可拖拽排序组件

新增一个组件,实时读取已经勾选的字段列表,生成对应的可拖拽的标签,用户拖拽标签就可以变更字段的顺序。
类似的效果如下:
可拖拽标签排序
该方案看起来更直观也更符合用户操作习惯,故下文基于该方案完成需求。

需求实现

表变更

因为展示端要读取排序信息,所以在现有的字段记录表中需要新增排序列,这里假设新增的排序列为 sort ,为 int类型 ,默认值为 -1

前端

引入组件

// 为 package.json 中的 dependencies 项新增如下属性
"vuedraggable": "^2.24.3"
// 相关页面引入 vuedraggable
import draggable from 'vuedraggable'

// 在vue中注册组件
components: {
    
    
    draggable
},

数据结构分析

  • fieldList 现有列表,存储所有的字段数据

    • 数据项中存在 id 属性,记录字段id
    • 数据项中存在 name 属性,记录字段名称
    • 数据项中存在 isChecked 属性,记录字段是否被勾选
    • 数据项中新增 sort 属性,记录字段排序信息(默认值为 -1,代表不参加排序)
  • fieldSortList 新增列表,数据结构同fieldList ,供排序组件读取信息

    • 在勾选或取消勾选字段之后,需要将 fieldList 中的已勾选字段同步至 fieldSortList
    • 在手动拖拽变更了字段顺序之后,需要将 fieldSortList 中的顺序信息同步至 fieldListsort

同步字段勾选信息

// 新增方法以更新字段排序列表
updatefieldSortList(){
    
    
  // 取出被勾选的字段
  let checkedItems = this.fieldList.filter((item) => item.isChecked)
  // 赋予新增字段(sort值为-1)序号
  let unSortItemList = checkedItems.filter(item => item.sort === -1)
  if (unSortItemList !== null && unSortItemList !== undefined && unSortItemList.length > 0) {
    
    
  	// 赋值:当前排序列表中的最大值+1(也即排序列表的当前长度-1)
    unSortItemList.forEach(unSortItem => unSortItem.sort = checkedItems.length - 1)
  }
  // 将字段信息按sort值排序,并将其复制至排序列表
  this.fieldSortList= JSON.parse(JSON.stringify(checkedItems.sort((a,b)=>a.sort-b.sort)))
}
<!-- 字段的勾选框,每个字段被勾选之后都会调用函数 checkboxChange -->
<el-checkbox @change="checkboxChange(fItem)"></el-checkbox>
// 在 checkboxChange 方法中新增更新操作
checkboxChange (item){
    
    
	// 省略现有逻辑
	console.log(item)
	// 勾选/取消勾选时更新字段排序列表
	this.updatefieldSortList()
}

// 在 created 中新建如下调用,用于在进入页面时生成可拖拽排序字段
this.updatefieldSortList();

展示排序列表

<!-- 引入自定义标题头,声明排序组件标题(可选) -->
<headTitle headTitle="所选字段排序"></headTitle>
<div class="fieldSortBox">
	<!-- 引入拖拽组件,读取排序列表数据 -->
	<draggable v-model="fieldSortList" class="dragItemCollection">
		<!-- 遍历排序列表数据,使用el-tag包裹数据项名称 -->
	    <div v-for="item in fieldSortList" :key="item.id" class="dragItem">
	      <el-tag type="info">{
   
   { item.name}}</el-tag>
	    </div>
	</draggable>
</div>
// 自定义样式,修饰排序组件内容
.fieldSortBox {
    
    
  margin-left: 130px;
  .dragItemCollection{
    
    
    display: inline-flex;
    flex-wrap: wrap;
    .dragItem {
    
    
      margin:5px 5px 5px 5px !important;
    }
  }
}

到这一步,页面应该能正常显示排序组件,排序组件也能随字段的勾选而同步变更,效果如下图:

同步勾选信息至排序列表

同步拖拽排序信息

// 新建侦听属性,侦听 fieldSortList 
watch:{
    
    
	fieldSortList: function (newVal, oldVal) {
    
    
      let sortId = 0
      // newVal 中的元素顺序即用户拖拽后看到的元素顺序
      newVal.forEach(sortItem=>{
    
    
        // 找到 fieldList 中对应的字段
        let fieldItem = this.fieldList.filter((item) => item.isChecked).find(item=>item.id = sortItem.id);
        // 将页面显示顺序设置为元素 sort 字段值
        fieldItem.sort = sortId++;
      })
    }
}

到此位置管理端的字段拖拽配置就完成了,可以在原有页面提交方法中在向后台提交数据前新增打印语句,检查拖拽后的顺序是否同步更新到字段数据项的 sort 字段。
最终效果如下图:
拖拽排序最终效果展示

展示端按顺序展示

方式1:后端排序

展示端请求后台数据时,后台按 sort 字段排序进行查询,并将结果返回前端,前端接收到后遍历展示即可。

QueryWrapper queryWrapper = new QueryWrapper<Field>().orderByAsc("sort");
return fieldService.list(queryWrapper);

方式2:前端排序

展示端请求后台数据时,后台直接查数据,并将结果返回前端,前端接收到后按 sort 值顺序展示即可。

总结

  • vuedraggable 可以完成前端拖拽操作,提供大量api可供自定义操作
  • 拖拽后的用户可视顺序为最终入库的排序值

参考文章

  1. vuedraggable开源库
  2. vue.draggable中文文档
  3. 手把手带你过一遍vue拖拽插件vuedraggable所有功能

猜你喜欢

转载自blog.csdn.net/Ka__ze/article/details/131321272