先来个效果图:
组件的实现是基于改变源数据的数组位置,所以使用的话必须要对传进去的源数据做一次深拷贝,操作完成后再传排序后的数组回去;
事件是采用了drag
系列事件,跟需求和用户操作习惯比较吻合;
图标是element-ui
里面的;
过度效果是vue的transition-group
标签实现的,这里要注意的是transition-group
包裹的次级元素一定要有唯一的key,而且依旧要设置transition
样式,否则不会有过度效果;
获取数组下标的处理方式不是特别好,希望路过的大神帮忙指点一下,蟹蟹;
下面是源码:
<template>
<ul class="dragSort">
<transition-group>
<li
draggable="true"
@dragstart="handlerDragstart"
@drag="handlerDrag"
@dragend="handlerDragend"
:id="index"
v-for="(item, index) in dataList"
:key="item.a">
【{{index+1}}】{{item.a}}
<i class="el-icon-sort"/>
</li>
</transition-group>
</ul>
</template>
<script>
export default {
props: {
},
name: 'dragSort',
data () {
return {
dataList: [
{ a: '测试类目-001' },
{ a: '测试类目-002' },
{ a: '测试类目-003' },
{ a: '测试类目-004' },
{ a: '测试类目-005' },
{ a: '测试类目-006' },
{ a: '测试类目-007' }
]
}
},
methods: {
handlerDragstart (e) {
const { y, target } = e
target.style.opacity = '.5'
target.oriY = y
target.oriIndex = Number(target.id)
},
handlerDrag (e) {
const { y, target } = e
if (y === 0) return
const offset = y - target.oriY
const length = this.dataList.length
if (Math.abs(offset) > target.offsetHeight) {
const index = target.oriIndex
const copyList = [...this.dataList]
let targetIndex = index + Math.round(offset / target.offsetHeight)
if (targetIndex > length - 1) {
targetIndex = length - 1
} else if (targetIndex < 0) {
targetIndex = 0
}
const readyToAppend = copyList.splice(index, 1)[0]
copyList.splice(targetIndex, 0, readyToAppend)
target.oriIndex = targetIndex
target.oriY = y
this.dataList = copyList
}
},
handlerDragend (e) {
const { y, target } = e
target.style.opacity = '1'
}
}
}
</script>
<style scoped lang="scss">
.dragSort{
width: 200px;
list-style: none;
margin: 0;
padding: 0;
li{
text-align: left;
border: 1px solid #f1f1f1;
padding: 10px;
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, .1);
border-radius: 5px;
margin-bottom: 10px;
cursor: move;
width: 100%;
background: #fff;
transition: all .3s;
z-index: 1;
i {
font-size: 16px;
color: #409EFF;
float: right;
}
}
}
</style>
转载请注明出处蟹蟹