uni-app拖拽排序

版本一代码,简洁:

<template>
	<view class='zhuti' @touchend='dragEnd'>
		<movable-area class="movable-area" :style='"display:"+movableViewInfo.showClass+"; height:"+"100%"+";"'>
			<movable-view class='row list-row movable-row' out-of-bounds='true' damping='99999' @change="viewsChang"
				:style='"height:"+pageInfo.rowHeight+"px;"' direction="vertical" :y="movableViewInfo.y">
				<view class='col1 content'>{{movableViewInfo.data.text}}</view>
				<view class="col3">
					<icon type='download' color='Gray' size='25' />
				</view>
			</movable-view>
		</movable-area>
		<scroll-view class="scroll-view_H" scroll-with-animation :scroll-y="isTrue">
			<block v-for="(item,index) in optionList">
				<view class='row list-row' v-show="action!=item.id" :style='"height: "+pageInfo.rowHeight+"px;"'>
					<view class='col1 content'>{{item.text}}</view>
					<view class="col3">
						<icon type='download' color='Gray' size='25' :data-action="item.id" :data-index='index'
							@touchstart='dragStart' @touchmove='dragMove' />
					</view>
				</view>
			</block>
		</scroll-view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				optionList: [{
						id: 1,
						text: "段落1 内容1"
					},
					{
						id: 2,
						text: "段落2 内容1"
					},
					{
						id: 3,
						text: "段落3 内容1"
					},
					{
						id: 4,
						text: "段落4 内容1"
					},
					{
						id: 5,
						text: "段落5 内容1"
					},
					{
						id: 6,
						text: "段落6 内容1"
					},
					{
						id: 7,
						text: "段落7 内容1"
					},
					{
						id: 8,
						text: "段落8 内容1"
					},
					{
						id: 9,
						text: "段落9 内容1"
					},
					{
						id: 10,
						text: "段落10 内容1"
					},
					{
						id: 11,
						text: "段落11 内容1"
					},
					{
						id: 12,
						text: "段落12 内容1"
					},
					{
						id: 13,
						text: "段落13 内容1"
					},
					{
						id: 14,
						text: "段落14 内容1"
					},

				],
				isTrue: true,
				isSorting: false,
				movableViewInfo: {
					y: 0,
					showClass: 'none', //'none' inline,
					data: {}
				},

				pageInfo: {
					rowHeight: 62,
					startIndex: null,
					scrollY: true,
					readyPlaceIndex: null,
					startY: 0,
					selectedIndex: null,
				},
				mainHeight: 0,
				moveH: 0,
				moveTop: 0,
				timer: null,
				outTime: null,
				heiBh: 0,
				//action是为了列表中隐藏当前拖拽的内容
				action: null
			}
		},
		onLoad() {
			const query = uni.createSelectorQuery().in(this);
			query.select('.zhuti').boundingClientRect(data => {
				this.mainHeight = data.height
			}).exec();
		},
		methods: {
			viewsChang(e) {

				this.heiBh = e.detail.y
				//定时间是拦截速度的,可以不用
				if (!this.timer) {
					this.timer = setInterval(() => {
						//1.7 和。1.3 是控制速度的,可以不用
						if (this.heiBh + (this.pageInfo.rowHeight * 1.7) >= this.mainHeight) {
							this.itemAdd(0)
						} else if (this.heiBh <= this.pageInfo.rowHeight / 1.3) {
							this.itemAdd(1)
						}
					}, 100)
				}
			},
			itemAdd(v) {
				this.isTrue = true
				if (this.outTime) return
				if (v == 0) {
					if (!this.optionList[this.pageInfo.selectedIndex + 1]) return this.isTrue = false
					this.outTime = setTimeout(() => {
						var selectedData = this.optionList[this.pageInfo.selectedIndex]
						this.optionList.splice(this.pageInfo.selectedIndex, 1)
						this.pageInfo.selectedIndex++
						this.optionList.splice(this.pageInfo.selectedIndex, 0, selectedData)
						this.outTime = null
					}, 100)
				} else {
					if (!this.optionList[this.pageInfo.selectedIndex + 1] || this.pageInfo.selectedIndex == 0)
						return this.isTrue = false
					this.outTime = setTimeout(() => {
						var selectedData = this.optionList[this.pageInfo.selectedIndex]
						this.optionList.splice(this.pageInfo.selectedIndex, 1)
						this.pageInfo.selectedIndex--
						this.optionList.splice(this.pageInfo.selectedIndex, 0, selectedData)
						this.outTime = null
					}, 100)

				}

			},
			dragStart(event) {
				this.isSorting = true
				var startIndex = event.target.dataset.index
				this.isTrue = false
				this.action = event.target.dataset.action
				// console.log('获取到的元素为', event, this.optionList[startIndex])
				// return
				// 初始化页面数据
				this.pageInfo.startY = event.touches[0].clientY
				this.pageInfo.readyPlaceIndex = startIndex
				this.pageInfo.selectedIndex = startIndex
				this.pageInfo.scrollY = false
				this.pageInfo.startIndex = startIndex
				this.movableViewInfo.y = this.pageInfo.startY - (this.pageInfo.rowHeight / 2)
				// 初始化拖动控件数据
				var movableViewInfo = this.movableViewInfo
				movableViewInfo.data = this.optionList[startIndex]
				movableViewInfo.showClass = "inline"
				this.movableViewInfo = movableViewInfo

			},
			dragMove(event) {
				// 计算拖拽距离
				var movedDistance = event.touches[0].clientY - this.pageInfo.startY
				this.movableViewInfo.y = this.pageInfo.startY - (this.pageInfo.rowHeight + 1 / 2) + movedDistance
				// console.log('移动的距离为', movedDistance)

				// 修改预计放置位置
				var movedIndex = parseInt(movedDistance / this.pageInfo.rowHeight)
				var readyPlaceIndex = this.pageInfo.startIndex + movedIndex
				if (readyPlaceIndex < 0) {
					readyPlaceIndex = 0
				} else if (readyPlaceIndex >= this.optionList.length) {

					readyPlaceIndex = this.optionList.length - 1
				}
				// console.log(event)
				if (readyPlaceIndex != this.pageInfo.selectedIndex) {
					var selectedData = this.optionList[this.pageInfo.selectedIndex]

					this.optionList.splice(this.pageInfo.selectedIndex, 1)
					this.optionList.splice(readyPlaceIndex, 0, selectedData)
					// console.log('======optionList',readyPlaceIndex)
					this.pageInfo.selectedIndex = readyPlaceIndex
				}
				// 移动movableView
				this.pageInfo.readyPlaceIndex = readyPlaceIndex
				// console.log('移动到了索引', readyPlaceIndex, '选项为', optionList[readyPlaceIndex])

			},
			dragEnd(event) {
				this.isSorting = false
				this.isTrue = true
				this.action = null
				// 重置页面数据
				this.pageInfo.readyPlaceIndex = null
				this.pageInfo.startY = null
				this.pageInfo.selectedIndex = null
				this.pageInfo.startIndex = null
				this.pageInfo.scrollY = true
				// 隐藏movableView
				this.movableViewInfo.showClass = 'none'
				clearInterval(this.timer)
				this.timer = null
			},
		}
	};
</script>

<style lang="scss">
	page {
		height: 100%;
		width: 100%;
	}

	.scroll-view_H {
		width: 100%;
		height: 100%;
		max-height: 100%;
	}

	.zhuti {
		height: 100%;
		width: 100%;
	}

	.row {
		height: 47px;
		width: 100%;

		display: flex;
		justify-content: space-around;
		align-items: center;
	}

	.title-row {
		border-bottom: 1px solid #888888;

		color: #888888;
	}

	.list-row {
		padding: 10px;
		border-bottom: 1px solid #D9D9D9;
		background-color: white;
		box-sizing: border-box;
		margin-bottom: 20px;
	}

	.movable-area {
		position: absolute;
		top: 0;
		left: 0;
		z-index: 10;
		width: 100%;
		// background: #F0AD4E;
	}

	.movable-row {
		box-shadow: #D9D9D9 0px 0px 20px;
		// background: #4CD964;
	}

	.col1 {
		width: 60%;
	}

	.col3 {
		width: 10%;
	}

	.content {
		font-size: 17px;

		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
	}
</style>
  • ios页面回弹
  • 当拖拽时需要禁用滚动

(行为不锁页面,驱动页面也会跟着挪动。意思就是,你拖动item时,影响到父级也滑动了

就像这样,紫色是父会跟着挪动到红色这

此处我是在开始拖拽中改变了isSorting为true,然后在我们的html中,通过这个值,判断当前的class,如果isSorting为true,那么overflow-y:hidden。如果isSorting为false,那么overflow-y:auto。

你可以做处理,当页面拖动个数*当个高度大于页面高度时,触发滚动条位置+ltem的一个高度
后续再优化

  • 对于pageInfo: {
                        rowHeight: 120,
                        scrollHeight: 120,
                        startIndex: null,
                        scrollY: true,
                        readyPlaceIndex: null,
                        startY: 0,
                        selectedIndex: null,
                    }中rowHeight: 120,
                        scrollHeight: 120,这两个高度,需要固定

而我实际使用中,我的项目item高度是不固定的,因此,我选择了一个最大的高度值,120。

  • 增加拖拽事件触发的范围

在拖拽的同级,增加一个view,然后让它绝对定位,宽高为100%,并且级别比他同级高即可

<view class="sort_action" style="position: relative;">
	<image src="../drag.png" class="sortIcon" style="z-index: 1;"></image>
	<text class="sortText" style="z-index: 1;">长按拖动</text>
	<view @touchstart='dragStart' @touchmove='dragMove' @touchend='dragEnd' :data-index='key' style="z-index: 2;position: absolute;top: 0;left: 0;width: 100%;height: 100%;">
	</view>
</view>
  • 拖拽时, 列表中隐藏当前拖拽的内容

看到另外一个组件:拖拽菜单 - DCloud 插件市场 有时间再继续研究

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值