目录
前言
本文记录了如何引入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
中的顺序信息同步至fieldList
的sort
- 在勾选或取消勾选字段之后,需要将
同步字段勾选信息
// 新增方法以更新字段排序列表
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可供自定义操作
- 拖拽后的用户可视顺序为最终入库的排序值