效果如下

代码如下
import React, { useState } from 'react'
import styles from './index.module.less'
import { View } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { useThrottleFn } from 'ahooks'
interface IProps {
list: any[]
itemHeight: number
renderItem: any
onchange: (value: any) => void
}
const DragSortList: React.FC<IProps> = (props) => {
const [list, setList] = useState(
props.list.map((item, index) => ({
...item,
top: index * props.itemHeight
}))
)
const [dragging, setDragging] = useState(null)
const [startY, setStartY] = useState(0)
const handleLongPress = (e, index) => {
Taro.vibrateShort()
setStartY(e.touches[0].clientY)
setDragging(index)
}
const { run: handleTouchMove } = useThrottleFn(
(e) => {
if (dragging === null) return
const newY = e.touches[0].clientY
const diff = newY - startY
let newTop = list[dragging].top + diff
newTop = Math.max(0, newTop)
newTop = Math.min(newTop, (list.length - 1) * props.itemHeight)
const currentIndex = Math.round(newTop / props.itemHeight)
if (currentIndex !== dragging) {
const newList = [...list]
const [draggingItem] = newList.splice(dragging, 1)
newList.splice(currentIndex, 0, draggingItem)
newList.forEach((item, index) => {
item.top = index * props.itemHeight
})
setList(newList)
setDragging(currentIndex)
}
setStartY(newY)
},
{ wait: 500 }
)
const handleTouchEnd = () => {
Taro.vibrateShort()
if (dragging === null) return
const targetIndex = Math.round(list[dragging].top / props.itemHeight)
const newList = [...list]
const movedItem = newList.splice(dragging, 1)[0]
newList.splice(targetIndex, 0, movedItem)
const arr = newList.map((item, index) => ({ ...item, top: index * props.itemHeight }))
setList(arr)
setDragging(null)
props.onchange(arr)
}
return (
<View className={styles.drag_list}>
{list.map((item, index) => (
<View
className={styles.drag_item}
key={item.id}
style={{
top: `${item.top}px`,
zIndex: dragging === index ? 999 : 1,
opacity: dragging === index ? 0.5 : 1
}}
onLongPress={(e) => {
console.log('【长按】', e)
handleLongPress(e, index)
}}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
>
{props.renderItem(item)}
</View>
))}
</View>
)
}
export default DragSortList
```js
.drag_list{
position: relative;
.drag_item{
background-color: #fff;
width: 100%;
position: absolute;
left: 0;
transition: top linear 0.3s;
}
}
使用
<DragSortList
list={[
{ id: 1, name: '集美仓' },
{ id: 2, name: '海沧仓' },
{ id: 3, name: '思明仓' },
{ id: 4, name: '湖里仓' }
]}
itemHeight={45}
renderItem={(item) => (
<View
style={{
height: 40,
lineHeight: '40px',
borderBottom: '1px solid #e8e8e8',
padding: '0 15px'
}}
>
<Icon name={'wap-nav'} /> {item.name}
</View>
)}
onchange={(e) => {
console.log(e)
}}
/>