|
vue elementUi+sortable.js嵌套表格拖拽
首先说下项目需求,一个多层嵌套的表格,行可以进行拖拽排序,但不能跨主级去拖拽,下拉可以异步获取数据,考虑了很久,还是用最熟悉的vue+element来做,但是element没有拖拽排序的功能,所以在此基础上加入sortable.js去实现拖拽功能。
后台返回的排序规则是 每个数据都带有3个属性 id next prev
用这3个属性实时的去更新排序
- id表示这一条数据的id
- next表示下一条数据的id
- prev表示上一条数据的id
html部分
data部分
- flattArray:[],
- originalData:[],
- tableData: [],
- arr:[],
- maps:new Map()
复制代码 我这里定义了四个数组和一个map
flattArray是平铺的数据 originalData数组也是平铺的数据(以防数据出错,没有啥实际用途) tableData是表格渲染的数据 arr是点击下拉异步请求的数据
maps是tableData改变后去重新渲染数据用的
methods部分
首先我定义了一个方法去深拷贝,这样改变一个数据的时候,其他数据不会改变- //深拷贝
- getNewObject(val) {
- let resObj = JSON.stringify(val);
- return JSON.parse(resObj);
- },
复制代码 加载页面从接口 获取 tableData数据 并深拷贝 tableData- getDetails(id){
- axios.get(url).then(res =>{
- if(res.data.code === 0){
- this.tableData = res.data.data
- this.tableData.map( item =>{
- item.hasChildren = true
- delete item.children
- })
- this.flattArray = this.getNewObject(this.tableData)
- this.originalData = this.getNewObject(this.tableData)
- }else{
- this.$message.error('网络错误');
- }
- }).catch(function (error) {
- this.$message.error('网络错误');
- });
- },
复制代码 这里表格就已经渲染出来了 ,因为下拉的数据要异步去获取,所以在element提供的下拉事件里面去请求数据,这里去获取子级的数据,并给maps赋值,利用递归,把数据平铺、组装。- //点击下拉图标异步加载数据
- load(tree, treeNode, resolve) {
- this.maps.set(tree.id, { tree, treeNode, resolve })
- axios.get(`url` + tree.id).then(res => {
- if (res.data.code == 0) {
- this.arr = res.data.data
- this.arr.map(item => {
- item.hasChildren = true
- delete item.children
- this.flattArray.push(item)
- })
- resolve(this.arr)
- const tree = buildTree(this.flattArray, 1);
- //组装tree
- function buildTree(nodes, parent) {
- const res = [];
- for (let item of nodes) {
- if (item.parentId === parent) {
- const children = buildTree(nodes, item.id);
- if (children.length) {
- item.children = children;
- }
- res.push(item);
- }
- }
- return res;
- }
- //平铺tree
- let result = [];
-
- function flatTree(nodes, parentId) {
- if (!nodes || nodes.length === 0) return [];
- nodes.forEach(node => {
- result.push(node);
- return flatTree(node.children, node.id);
- });
- }
- flatTree(tree, 1);
-
- this.originalData = result
- this.getNewObject(this.originalData)
- } else {
- this.$message.error('没有更多消息了');
- }
- })
- },
复制代码 定义的行拖拽方法,因为排序是用的3个属性去排序的,所以有3种情况去考虑
- 一是拖动到最上级,这样prev的值就为空
- 二是拖动到最下级,next为空
- 三是正常的拖动,next prev都不为空
- rowDrop() {
- this.$nextTick(() => {
- const tbody = document.querySelector('.el-table__body-wrapper tbody')
- const _this = this
- Sortable.create(tbody, {
- animation: 300,
- sort: true,
- onEnd({
- oldIndex,
- newIndex,
- item
- }) {
- const sourceObj = _this.originalData[oldIndex - 1] // 原本的位置
- const targetObj = _this.originalData[newIndex - 1] // 移动到的位置
- const frontObj = _this.originalData[newIndex - 2] //移动后位置的上一级
- const behindObj = _this.originalData[newIndex] //移动后位置的下一级
- if(sourceObj.parentId != targetObj.parentId) {
- _this.$message.error("不支持跨级拖动,请拖回原来位置")
- location.reload();
- return;
- }
- let data = [];
- if( oldIndex < newIndex ){//向下移动
- //上一级
- let predata = {
- id: targetObj.id,
- next: sourceObj.id,
- prev: targetObj.prev
- }
- //自己
- let curdata = {
- id: sourceObj.id,
- next: targetObj.next,
- prev: targetObj.id,
- groupId: sourceObj.groupId
- }
- //下一级
- let nextdata = null
- if (behindObj != undefined && sourceObj.parentId == behindObj.parentId) {
- nextdata = {
- id: behindObj.id,
- next: behindObj.next,
- prev: sourceObj.id
- }
- }
- if(nextdata){
- data.push(curdata, predata, nextdata)
- }else{
- data.push(curdata, predata)
- }
- _this.postdata(data, sourceObj.parentId)
- }else if( oldIndex > newIndex ){//向上移动
- //上一级
- let predata = null
- if (frontObj != undefined && sourceObj.parentId == frontObj.parentId) {
- predata = {
- id: frontObj.id,
- next: sourceObj.id,
- prev: frontObj.prev
- }
- }
- //自己
- let curdata = {
- id: sourceObj.id,
- next: targetObj.id,
- prev: targetObj.prev,
- groupId: sourceObj.groupId
- }
- //下一级
- let nextdata = {
- id: targetObj.id,
- next: targetObj.next,
- prev: sourceObj.id
- }
-
- if(predata){
- data.push(curdata, predata, nextdata)
- }else{
- data.push(curdata, nextdata)
- }
- _this.postdata(data, sourceObj.parentId)
- }
- }
- })
- })
- },
复制代码 mounted 里面去加载 改变行的方法- mounted() {
- this.rowDrop()
- },
复制代码 最后再去动态的更新数据- refreshLoadTree(parentId) {
- // 根据父级id取出对应节点数据
- const {tree, treeNode, resolve} = this.maps.get(parentId)
- this.$set(this.$refs.tableData.store.states.lazyTreeNodeMap, parentId, [])
- if (tree) {
- this.load(tree, treeNode, resolve)
- }
- },
复制代码 到这里需求已经实现了,就没有去深入的挖掘,可能会有问题,但是隔的时间太久了,基本忘光了。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
来源:https://www.jb51.net/javascript/322400cb3.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|