当前位置: 首页 - 编程技术 - 文章正文

【关于Vue + Ts + Sortable实现列表间拖拽实现及遇到的问题】

xiaoqihv

关于Vue + Ts + Sortable实现列表间拖拽实现及遇到的问题 实现过程遇到的问题效果展示补充:http://www.sortablejs.com/options.html (sortable网址)

实现过程

直接上代码: 我这里是直接写的table,里面可能有些业务逻辑,可以忽略不计。 关键是这里我写了两个tbody用于拖拽

<table> <thead class="thead"> <tr class="navTable"> <th> 序号 </th> <th> 攻略类型 </th> <th> 攻略标题 </th> <th> 分类标签 </th> <th> 封面预览 </th> <th> 投稿时间 </th> <th> 审核时间 </th><th> 投稿人 </th> <th> QQ </th> <th> <div> <div>排序</div> </div> </th> </tr> </thead> <tbody ref="sortBody" class="topBody" > <tr v-for="item in topList" :key="item.sortNum" class="sortContent" > <td :value="item.sortNum" class="reduceItem" > <el-button type="text" class="topReduce" size="medium" @click="topReduce(item)" > - </el-button> <span class="reduceItem topItemStyle">置顶{{ item.sortNum > 30 ? topList.length : item.sortNum }}</span> </td> <td :value="item.type" class="typeItem" > <el-tag :type="item.type === 1 ? 'primary' : 'success'"> {{ item.type === 1 ? '图文' : '视频' }} </el-tag> </td> <td :value="item.title" class="authorItem titleItem" > {{ item.title }} </td> <td :value="item.tagList" class="tagList" > <el-tag v-for="i in item.tagList" :key="i.index" type="success" class="tagItem" > {{ i }} </el-tag> </td> <td :value="item.cover" class="authorItem" > <img :src="item.cover" fit="contain" style="width: 100px; height: 100px;" > </td> <td :value="item.createTime" class="authItem" > {{ item.createTime | parseTime('{y}-{m}-{d} {h}:{i}:{s}') }} </td> <td :value="item.authTime" class="authItem authTime" > {{ item.authTime | parseTime('{y}-{m}-{d} {h}:{i}:{s}') }} </td> <td :value="item.author" class="authorItem author" > {{ item.author }} </td> <td :value="item.qq" class="authorItem" > {{ item.qq }} </td> <td class="sortIcon"> <img src="@/assets/sort-icon/sort.png" style="width: 40px; height: 40px;" class="sortImg" > </td> </tr> </tbody> <div class="topAdd" > <p v-if="topList.length < 3" type="text" class="addBtn" size="medium" > 以上为置顶列表,数量最多为3 </p> <p v-else type="text" class="addBtn" size="medium" > 置顶列表数量为3,已满 </p> </div> <tbody ref="sortBody" class="sortBody" > <tr v-for="item in sortList" :key="item.sortNum" class="sortContent" > <td :value="item.sortNum"> {{ item.sortNum > 30 ? '待排序' : item.sortNum }} </td> <td :value="item.type" class="typeItem" > <el-tag :type="item.type === 1 ? 'primary' : 'success'"> {{ item.type === 1 ? '图文' : '视频' }} </el-tag> </td> <td :value="item.title" class="authorItem titleItem" > {{ item.title }} </td> <td :value="item.tagList" class="tagList" > <el-tag v-for="i in item.tagList" :key="i.index" type="success" class="tagItem" > {{ i }} </el-tag> </td> <td :value="item.cover" class="authorItem" > <img :src="item.cover" fit="contain" style="width: 100px; height: 100px;" > </td> <td :value="item.createTime" class="authItem" > {{ item.createTime | parseTime('{y}-{m}-{d} {h}:{i}:{s}') }} </td> <td :value="item.authTime" class="authItem authTime" > {{ item.authTime | parseTime('{y}-{m}-{d} {h}:{i}:{s}') }} </td> <td :value="item.author" class="authorItem author" > {{ item.author }} </td> <td :value="item.qq" class="authorItem" > {{ item.qq }} </td> <td class="sortIcon"> <img src="@/assets/sort-icon/sort.png" style="width: 40px; height: 40px;" class="sortImg" > </td> </tr> </tbody> </table>

下面是逻辑部分,感觉还是有很多坑容易踩的。 重点:如果是多个列表间实现拖拽,那么一定不可以使用onEnd,要用onUpdate

public rowDrop() { const sortBody = document.querySelector('.topBody') // eslint-disable-next-line @typescript-eslint/no-this-alias const _this = this Sortable.create(sortBody, { animaton: 300, group: { name: 'shared', pull: true, put: function() { if (_this.topList.length > 3) { return false } else if (_this.topList.length === 3) { return false } else { return true } } }, easing: 'cubic-bezier(1, 0, 0, 1)', handle: '.sortImg', onUpdate: function(evt:any) { const currRow = _this.topList.splice(evt.oldIndex, 1)[0] _this.topList.splice(evt.newIndex, 0, currRow) console.log('this.topList--end', _this.topList) }, onAdd: function(evt:any) { console.log('evt.newIndex', evt.newIndex) _this.topList.splice(evt.newIndex, 0, _this.sortList[evt.oldIndex]) _this.topList.forEach(item => { (item as any).top = true }) console.log('_this.topList--add', _this.topList) } }) const sortBody1 = document.querySelector('.sortBody') // eslint-disable-next-line @typescript-eslint/no-this-alias const that = this Sortable.create(sortBody1, { animaton: 300, group: { name: 'shared', put: false, pull: function() { if (that.topList.length > 3) { return false } else if (that.topList.length === 3) { return false } else { return true } } }, easing: 'cubic-bezier(1, 0, 0, 1)', handle: '.sortImg', onUpdate: function(evt:any) { const currRow = that.sortList.splice(evt.oldIndex, 1)[0] that.sortList.splice(evt.newIndex, 0, currRow) console.log('this.sortList--end', that.sortList) }, onRemove: function(evt:any) { that.sortList.splice(evt.oldIndex, 1) console.log('that.sortList--remove', that.sortList) } }) } 遇到的问题 由于我这里是在弹窗内部写的拖拽,所以最初的dom并没有渲染,这个时候存在找不到可拖拽的dom的问题。 解决:这个时候需要在打开弹窗的地方调用拖拽的那个方法 this.$nextTick(() => { this.rowDrop() }) 由于我在列表间拖拽使用onEnd函数处理数据,导致会报插入子节点的错误。 解决:换成onUpdate函数处理数据就可以了最初我把列表间的分割线和第一个拖拽列表写在一起了,导致拖拽一直有问题。 效果展示

补充:http://www.sortablejs.com/options.html (sortable网址)
文章地址:https://wenmayi.cn/post/102.html