Files
xk-doctor-wx/components/d-dragSorts/d-dragSorts.vue
2024-09-19 12:57:55 +08:00

326 lines
8.8 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="p-row-32 white">
<movable-area :style="{ height: `${areaHeight}px`}">
<block v-for="(item, index) in list" :key="index">
<movable-view :key="item.sign" @change="e => change(e, index)" @touchend="touchend"
@touchstart="touchstart($event);touchStart(index)" class="drag_item"
:y="item.y" direction="vertical" :disabled='disabled' :style="{zIndex:`${current==index?2:1}`}">
<u-swipe-action :disabled="isSlide" :show="item.show" :index="index" :key="item.sign" @click="click"
@open="open" :options="options" :style="{zIndex:list.length-index}">
<view class="touch_view"
:style="{minHeight: item.itemHeight?item.itemHeight+'px':itemHeight+'px',borderBottom: (index+1)!=list.length?'1px solid #E8E9EB':'1px solid #fff',paddingTop: ifCustomHeight?'48rpx':'32rpx'}"
@click="$emit('click',item)">
<view class="left">
<text>{{ item[name]}}</text>
</view>
<view class="right">
<u-icon size="40" color="#B7B7BA" name="list"></u-icon>
</view>
</view>
</u-swipe-action>
</movable-view>
</block>
</movable-area>
</view>
</template>
<script>
export default {
props: {
ifCustomHeight: {
type: Boolean,
default: false
},
propList: {
type: Array,
default: () => []
},
isSlide: {
type: Boolean,
default: false
},
height: {
type: Number,
default: 104
},
name: {
type: String,
default: 'name'
},
},
data() {
return {
longpress: false,
oldIndex: -1, //记录移动前的位置,为了和移动后进行比较是否发生了位移
newIndex: -1, //当前移动到的位置
direction: '',
current: -1,
itemHeight: uni.upx2px(this.height),
difference: 0, //记录移动前的位置
disabled: true, //是否可以拖动
list: [], //渲染的list
options: [{
text: '删除',
style: {
backgroundColor: '#dd524d'
}
}],
timer: null,
startX: 0, //touchStart开始坐标
startY: 0,
};
},
created() {
this.ifCustomHeight && this.getElRect()
},
computed: {
areaHeight() {
let height = this.list.reduce((to, item) => {
to += (item.itemHeight || this.itemHeight)
return to
}, 0)
return height
},
},
watch: {
propList: {
handler(val) {
this.list = this.updateList(val);
this.cloneList = JSON.parse(JSON.stringify(this.list));
},
immediate: true,
deep: true
}
},
methods: {
// 计算滑动角度
touchstart(e) {
this.startX = e.changedTouches[0].clientX,
this.startY = e.changedTouches[0].clientY
},
//计算滑动角度 start 起点坐标 end 终点坐标
angle(start, end) {
var _X = end.X - start.X,
_Y = end.Y - start.Y;
//返回角度 Math.atan()返回数字的反正切值
return 360 * Math.atan(_Y / _X) / (2 * Math.PI);
},
getDirection(e) {
let {
startX,
startY
} = this;
let slidingRange = 45;
let touchMoveX = e.changedTouches[0].clientX;
let touchMoveY = e.changedTouches[0].clientY;
let angle = this.angle({
X: startX,
Y: startY
}, {
X: touchMoveX,
Y: touchMoveY
});
//为了方便计算取绝对值判断
if (Math.abs(angle) > slidingRange && touchMoveY < startY) {
// 向上滑动
this.direction = 'up'
};
if (Math.abs(angle) > slidingRange && touchMoveY > startY) {
// 向下滑动
this.direction = 'down'
}
},
// 获取一个目标元素的高度
getElRect() {
let query = uni.createSelectorQuery().in(this);
query.selectAll('.drag_item').boundingClientRect(res => {
// 如果节点尚未生成res值为null循环调用执行
if (res.length == 0) {
setTimeout(() => {
this.getElRect();
}, 10);
return;
}
for (let i = 0; i < res.length; i++) {
this.$set(this.list[i], 'itemHeight', res[i].height < this.itemHeight ? this.itemHeight :
res[i].height)
this.$set(this.list[i], 'y', this.getTop(this.list, i))
}
this.updateList(this.list)
this.cloneList = JSON.parse(JSON.stringify(this.list));
}).exec();
},
getTop(list = [], end = 0) {
let itemHeight = 0
for (let i = 0; i < list.length; i++) {
if (end == i) {
break
}
itemHeight += list[i]['itemHeight']
}
return itemHeight
},
// 添加或更新数组y值
updateList(list = []) {
return list.map((item, index) => {
let obj = {
...item,
show: false,
sign: Math.random() + index //防止不更新的情况和标识位
}
if (this.ifCustomHeight) {
return obj;
} else {
return {
...obj,
y: index * this.itemHeight
};
}
});
},
touchStart(index) {
this.disabled = false
this.current = index;
this.oldIndex = index;
},
change(e, index) {
// 不是当前元素位移直接不处理
if (index != this.current) return;
this.longpress = true
if (this.ifCustomHeight) {
this.difference = e.detail.y;
} else {
//位移的距离px
let difference = e.detail.y - this.current * this.itemHeight;
//计算位移几个位置
let tempIndex = difference > 0 ? parseInt((difference + (this.itemHeight / 2)) / this.itemHeight) :
parseInt((difference - (this.itemHeight / 2)) / this.itemHeight);
//当前拖到的位置
this.newIndex = Math.abs(this.current + tempIndex);
if (this.newIndex > -1 && this.oldIndex > -1 && this.newIndex !== this.oldIndex) {
this.changeList();
}
}
},
changeList() {
// 没想到怎么改变原数组, 直接拷贝一份数组出来,不考虑情况 一把梭 直接遍历拷贝的原数组.
//直接把改变位置赋值回去不行不知道为什么只能改变每一项的y值
let arr = JSON.parse(JSON.stringify(this.cloneList));
arr.splice(this.newIndex, 0, ...arr.splice(this.current, 1));
this.list.forEach((item, index) => {
if (index !== this.current) {
item.y = arr.findIndex(citem => citem.sign == item.sign) * this.itemHeight;
}
});
this.oldIndex = this.newIndex;
},
touchend(e) {
if (!this.longpress) {
return
}
if (this.ifCustomHeight) {
if (!this.list[this.current] || this.current < 0) {
return
}
this.getDirection(e)
let itemHeight = this.list[this.current]['itemHeight'];
console.log(this.difference);
let difference = this.difference;
let arr = JSON.parse(JSON.stringify(this.cloneList));
let index = this.current;
for (var i = 0; i < arr.length; i++) {
let item = arr[i]['y'] + arr[i]['itemHeight'] / 2
if (this.direction == 'down' && difference + itemHeight >= item) {
index = i
} else if (this.direction == 'up' && item >= difference) {
index = i
break
}
}
index >= 0 && arr.splice(index, 0, ...arr.splice(this.current, 1));
for (var i = 0; i < arr.length; i++) {
arr[i]['y'] = this.getTop(arr, i)
}
this.list = this.updateList(arr);
} else {
if (this.newIndex > -1 && this.current > -1 && this.newIndex !== this.current) {
this.cloneList.splice(this.newIndex, 0, ...this.cloneList.splice(this.current, 1));
this.list = this.updateList(this.cloneList);
}
}
this.cloneList = JSON.parse(JSON.stringify(this.list));
this.emitChang(this.list)
this.current = -1;
this.oldIndex = -1;
this.newIndex = -1;
this.disabled = true
this.difference=0
this.longpress = false
},
click(index, index1) {
if (index1 == 0) {
this.$emit('del', index)
}
},
// 如果打开一个的时候,不需要关闭其他,则无需实现本方法
open(index) {
// 先将正在被操作的swipeAction标记为打开状态否则由于props的特性限制
// 原本为'false',再次设置为'false'会无效
this.list[index].show = true;
this.list.map((val, idx) => {
if (index != idx) this.list[idx].show = false;
});
},
emitChang(arr) {
let tempArr = JSON.parse(JSON.stringify(arr))
tempArr.forEach(item => {
delete item.y
delete item.show
delete item.sign
})
this.$emit('change', tempArr)
}
}
};
</script>
<style lang="scss">
.drag_item {
width: 686rpx;
background-color: #fff;
height: max-content;
}
movable-area {
width: 686rpx;
background-color: #fff;
}
.touch_view {
width: 686rpx;
display: flex;
justify-content: space-between;
align-items: flex-start;
.left {
display: flex;
align-items: center;
padding-bottom: 16rpx;
padding-right: 16rpx;
text {
font-size: 28rpx;
color: #31353D;
}
}
.right {
width: 40rpx;
height: 40rpx;
background: #FFFFFF;
box-shadow: 0px 0px 8rpx 0px rgba(0, 0, 0, 0.08);
border-radius: 4rpx;
}
}
</style>