uniapp 实现左右拖动换位子 删除新增
因工作需要做的一个小逻辑 记录一下
效果图如下
index.vue代码如下
<template>
<view class="wh-100" style="background-color: #F2F4F9;">
<view style="height: 40rpx;width: 100%;"></view>
<view class="flex flex-column bgCss">
<view class="titleCss">首页按键区<text class="textCss">(长按选中拖动替换首页展示按键顺序)</text></view>
<view class="flex align-center justify-center" style="width: 610rpx;height: 210rpx;margin: 0 auto;" >
<DragSorts @change="sortChange" @click="click" @del="moduleDel" :viewWidth="610 / 2" :row="4"
:disabled="!editing" :list="dataArray" :extraNodes="extraList" :isDragSorts="isDragSorts">
<template v-slot:rowContent="{ row, disabled }">
<view @click="click(row)" class="item" >
<image @click.stop="moduleDel(row)" v-if="row.label!='6'" src="/static/customizeKeys/img/icon-delet.png" mode="widthFix" style="width: 30rpx; height: 30rpx;position: absolute;top: -8rpx;left: 120rpx;z-index: 99;"></image>
<image class="itemImg" :src="row.imgSrc" mode="aspectFit|aspectFill|widthFix"></image>
</view>
</template>
</DragSorts>
</view>
</view>
<view class="flex flex-column bgCss" style="margin-top: 18rpx;">
<view class="titleCss" >功能按键<text class="textCss">(长按选中可拖动至上方按键区)</text>
</view>
<view class="flex align-center justify-center" style="width: 610rpx;flex-wrap: wrap;min-height: 210rpx; margin: 0 auto;">
<view class="flex align-center justify-center" v-for="(item, index) in addList" :key="index" style="position: relative;width: 25%;">
<image v-if="item.imgSrc" @click="getAdd(item,index)" src="/static/customizeKeys/img/icon-add.png" mode="widthFix"
style="width: 30rpx; height: 30rpx;position: absolute;top: -8rpx;left: 120rpx;z-index: 99;">
</image>
<image :src="item.imgSrc" mode="widthFix" style="width: 120rpx; height: 120rpx;"></image>
</view>
</view>
</view>
<view class="flex align-center" style="position: absolute;bottom: 80rpx; margin: 0 auto;width: 100%;">
<button type="default" class="btnCss" :disabled="isdisabled" :class="isdisabled? 'isdisabledCss':''">
保存按键
</button>
</view>
</view>
</template>
<script>
import DragSorts from "components/evils-drag-sorts/index.vue";
export default {
components: {
DragSorts,
},
data() {
return {
// 这个内容可以自定义
dataArray: [{
imgSrc: '/static/customizeKeys/img/jiesuo.png',
label: '1'
},
{
imgSrc: '/static/customizeKeys/img/suoche.png',
label: '2'
},
{
imgSrc: '/static/customizeKeys/img/weixiang.png',
label: '3'
},
{
imgSrc: '/static/customizeKeys/img/qidong.png',
label: '4'
},
],
nullList: [{
imgSrc: '/static/customizeKeys/img/add.png',
label: '6',
type: 'add'
}, ],
addList: [{
imgSrc: '/static/customizeKeys/img/xunche.png',
label: '5'
},{},{},{}],
isdisabled: false,
editing:true,
// 额外元素 不参与拖动
extraList: [],
isDragSorts:true,
}
},
onLoad() {
},
methods: {
// 排序完成
sortChange(val) {
console.log(`val`, val);
},
// 元素被点击
click(e) {
console.log(`click`, e);
},
// 元素删除
moduleDel(data) {
var that = this
console.log(`moduleDel111111111`, );
let id = data.label
let index = 0
for (var i = 0; i < that.dataArray.length; i++) {
if (id == that.dataArray[i].label) {
index = i
}
}
// 功能按键
let indexaa=-1
for (var i = 0; i < that.addList.length; i++) {
if (!that.addList[i].imgSrc) {
indexaa = i
break
}
}
that.addList[indexaa] = that.dataArray[index]
// that.addList = that.addList.concat(that.dataArray[index])
// 首页按键区
that.dataArray.splice(index, 1);
that.dataArray = that.dataArray.concat(that.nullList)
that.isDragSorts=!that.isDragSorts
console.log('that.dataArray', that.dataArray, that.addList)
},
getAdd(data, index) {
var that = this
// 首页按键区
let indexaa = -1
for (var i = 0; i < that.dataArray.length; i++) {
if (that.dataArray[i].type == 'add') {
indexaa = i
break
}
}
if(indexaa==-1){
uni.$u.toast('首页按钮区只能配置四个按钮');
return
}
that.dataArray[indexaa] = data;
// 功能按键
that.addList.splice(index, 1);
if(that.addList.length<4){
let lengg=4-that.addList.length
for (var i = 0; i < lengg; i++) {
that.addList.push({})
}
}
that.isDragSorts=!that.isDragSorts
console.log('that.dataArray', that.dataArray)
}
}
}
</script>
<style scoped>
.bgCss {
width: 670rpx;
background: #FFFFFF;
border-radius: 24rpx;
margin: 0 auto;
font-size: 28rpx;
}
.titleCss {
font-weight: 500;
color: #0F1E4C;
font-size: 28rpx;
padding-top: 34rpx;
padding-left: 36rpx;
}
.textCss {
font-weight: 400;
color: #999999;
font-size: 24rpx;
padding-left: 8rpx;
}
.btnCss {
background: #00245D;
border-radius: 24rpx;
width: 580rpx;
color: #fff;
}
.isdisabledCss {
background: #00245D !important;
}
.item {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 20rpx;
position: relative;
}
.itemImg {
width: 120rpx;
height: 120rpx;
}
</style>
evils-drag-sorts 组件代码如下
<template>
<view class="">
<movable-area
id="drag"
class="drag-sort"
:style="{ height: boxHeight, width: viewWidth + 'px', margin: margin }"
>
<!-- @touchstart="touchstart" -->
<movable-view
v-for="(item, index) in currentList"
:key="index"
:x="item.x"
@touchmove.stop="touchmove"
@touchend="touchstart"
:data-fixed="item.fixed"
:data-index="index"
:y="item.y"
:direction="direction"
disabled
damping="40"
:animation="item.animation"
class="drag-sort-item w-4"
:class="active == index ? 'active' + Style : '' + Style"
>
<view class="slotBox" :class="!disabled && animate ? 'animate' : ''">
<slot
name="rowContent"
:disabled="
!item.type && !disabled && !row.close && active !== index
"
:row="item"
></slot>
</view>
</movable-view>
</movable-area>
</view>
</template>
<script>
const app = getApp();
export default {
name: "drag-sort",
mixins: [],
components: {},
data() {
return {
imgUrl: app.globalData.imgUrl,
direction: "all",
currentList: [],
del: false, // 删除中
active: -1, // 当前激活的item
index: 0, // 当前激活的item的原index
topY: 40, // 距离顶部的距离
topX: 40, // 距离左侧偏移位置
columns: 1, // 列数
};
},
computed: {
boxHeight() {
return (
Math.ceil(Number(this.currentList.length) / this.row) * this.height +
"px"
);
},
Style() {
return `w-${this.row}`;
},
},
props: {
//是否禁用拖拽生效(常用于拖拽开关)
disabled: {
type: Boolean,
default: true,
},
// 单个元素高度
height: {
type: Number,
default: 80,
},
// 整体偏移
margin: {
type: String,
default: "0 0 0 0",
},
// 需要拖拽的项目列表
list: {
type: Array,
default: () => {
return [];
},
},
// 每行元素个数
row: {
type: Number,
default: 5,
},
// 拖拽元素区域宽度,用于位置计算
viewWidth: {
type: Number,
default: 686 / 2,
},
// 是否开启抖动动画
animate: {
type: Boolean,
default: false,
},
// 额外的元素(不参与拖拽排序)
extraNodes: {
type: Array,
default: [
// {
// type: 'before',
// index: 0,
// module_icon: app.globalData.imgUrl + '/modulesIcon/resultsQuery.png',
// url: '',
// module_name: '成绩查询',
// module_alias: 'before'
// },
],
},
isDragSorts:{
type: Boolean,
default: false,
},
},
watch: {
list: {
// 监听列表更改更新数据
handler() {
this.onUpdateCurrentList();
},
deep: true
},
isDragSorts:{
handler() {
this.onUpdateCurrentList();
},
deep: true
},
disabled: {
// 用于拖拽完成后开关回传
handler(newVal, oldVal) {
if (newVal && newVal !== oldVal) {
this.$emit("change", this.currentList);
}
},
},
},
created() {
this.onUpdateCurrentList();
},
methods: {
click(e) {
this.$emit("click", e);
},
moduleDel() {
this.del = true;
// this.$emit("del", e);
console.log(`this.del11111111111`,this.del);
setTimeout(() => {
console.log(`moduleDel`);
this.del = false;
}, 200);
},
// 计算元素的位置
listXY(key) {
const NUM = this.row;
let x = 0;
let row = Math.floor(Number(key) / NUM);
x = (Number(key) % NUM) * (this.viewWidth / NUM);
let y = row * this.height;
return {
x,
y,
width: this.viewWidth / NUM,
};
},
// 生成可拖拽元素列表
onUpdateCurrentList(list = this.list) {
console.log("1111111111111111111111")
let delItem = (item, extraNode, index) => ({
isShow: 1, // 是否显示
fixed: extraNode ? true : false,
close: item.isdefault,
extraNode,
realKeyindex: Number(index),
...item,
animation: true,
});
let _list = [],
_before = [],
_after = [],
destBefore = [],
destAfter = [];
// this.extraNodes.forEach((item, index) => {
// if (item.type === "before") {
// _before.push(delItem(item, true, -1));
// } else if (item.type === "after") {
// _after.push(delItem(item, true, -1));
// } else if (item.type === "destBefore") {
// destBefore.push(delItem(item, true, item.index));
// } else if (item.type === "destAfter") {
// destAfter.push(delItem(item, true, item.index));
// }
// });
// 遍历数据源增加扩展项, 以用作排序使用
list.forEach((item, index) => {
destBefore.forEach((i) => {
if (i.index === index) _list.push(i);
});
_list.push(delItem(item, item.fixed, index));
destAfter.forEach((i) => {
if (i.index === index) _list.push(i);
});
});
let tempList = _before.concat(_list, _after) || [];
console.log('tempList',tempList)
let arr = [];
for (const key in tempList) {
arr.push({
isShow: 1, // 是否显示
// fixed: Number(key) % 2,
...tempList[key],
realKey: tempList[key].extraNode ? -1 : Number(key), // 真实顺序
sortKey: Number(key),
index: Number(key),
...this.listXY(key),
animation: true,
});
}
this.currentList = arr.filter((v) => v.isShow);
},
// 根据排序进行重新计算位置
moveUpdateCurrentList(index) {
for (const i in this.currentList) {
let key;
if (this.currentList[i].sortKey || this.currentList[i].sortKey === 0) {
key = this.currentList[i].sortKey;
} else {
key = Number(i);
}
if (index == key && this.currentList[i].fixed) {
continue;
} else {
let data = this.listXY(key);
this.currentList[i].x = data.x;
this.currentList[i].y = data.y;
console.log('this.currentList[i].x',this.currentList[i].x)
}
}
if (this.disabled) return;
// this.$emit('change', this.currentList);
},
touchstart(e) {
let fixed = Number(e.currentTarget.dataset.fixed);
if (this.disabled || fixed || this.del) return;
// 计算 x y 轴点击位置
console.log(`this.del`, this.del,this.disabled);
setTimeout(() => {
if (this.del) return;
console.log(`touchstart`, e);
var query = uni.createSelectorQuery().in(this);
query.select("#drag").boundingClientRect();
let index = Number(e.currentTarget.dataset.index);
query.exec((res) => {
this.topY = res[0].top;
this.topX = res[0].left;
this.active = index;
this.index = index;
// let temY = e.mp.touches[0].clientY - this.topY;
// let temX = e.mp.touches[0].clientX - this.topX;
// let touchY = temY - this.height / 2;
// let touchX = temX;
// this.currentList[this.active].animation = false;
// this.currentList[this.active].y = touchY;
// this.currentList[this.active].x = touchX;
});
}, 100);
this.touchend(e)
},
touchmove(e) {
if (this.active < 0) return;
let temY = e.mp.touches[0].clientY - this.topY;
let temX = e.mp.touches[0].clientX - this.topX;
let touchY = temY - this.height / 2;
let touchX = temX;
this.currentList[this.active].y = touchY;
this.currentList[this.active].x = touchX;
this.currentList[this.active].animation = false;
this.currentList.every((res, index) => {
let absX = Math.abs(touchX - res.x);
let absY = Math.abs(touchY - res.y);
// 设置元素定点距离多少进行重排
if (
0 < absX &&
absX <= this.viewWidth / this.row / 2 &&
absY > 0 &&
absY <= this.height / 2 &&
this.active != index &&
!res.fixed
) {
// debugger
let temNumber = this.currentList[index].sortKey;
this.currentList.every((_res, _index) => {
// 判断从大像小移还是从小向大移
if (
this.currentList[this.active].sortKey <
this.currentList[index].sortKey
) {
// 移动元素比目标元素所在位置小,之间元素排序--
if (
this.currentList[_index].sortKey >
this.currentList[this.active].sortKey &&
this.currentList[_index].sortKey <=
this.currentList[index].sortKey
) {
_res.sortKey--;
}
} else {
// 反之++
if (
this.currentList[_index].sortKey <
this.currentList[this.active].sortKey &&
this.currentList[_index].sortKey >=
this.currentList[index].sortKey
) {
_res.sortKey++;
}
}
return true;
}, this);
this.currentList[this.active].sortKey = temNumber;
this.moveUpdateCurrentList(temNumber);
return false;
} else {
return true;
}
}, this);
},
touchend(e) {
if (this.currentList[this.active]) {
this.currentList[this.active].animation = true;
}
this.moveUpdateCurrentList(-1);
this.active = -1;
},
},
};
</script>
<style lang="scss" scoped>
.slotBox {
width: 100%;
height: 100%;
.item {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 24rpx;
.itemImg {
width: 94rpx;
height: 94rpx;
}
.itemName {
padding-top: 8rpx;
color: #a1a1a1;
width: 100%;
font-size: 26rpx;
text-align: center;
overflow: hidden; //超出的文本隐藏
white-space: nowrap; //溢出不换行
text-overflow: ellipsis; //溢出用省略号显示
display: -webkit-box; //作为弹性伸缩盒子模型显示。
-webkit-box-orient: vertical; //设置伸缩盒子的子元素排列方式--从上到下垂直排列
-webkit-line-clamp: 1; //显示的行
}
.itemDel {
position: absolute;
top: -17rpx;
right: 0rpx;
image {
width: 34rpx;
height: 34rpx;
}
}
}
}
// .drag-sort {
// width: 100%;
// }
.w-1 {
width: 100%;
}
.w-2 {
width: 50%;
}
.w-3 {
width: 33.3333%;
}
.w-4 {
width: 25%;
}
.w-5 {
width: 20%;
}
.w-6 {
width: 16.666666%;
}
.ev-width-b100 {
width: 100%;
}
.drag-sort-item {
position: absolute !important;
display: flex;
height: 80rpx;
align-items: center;
text-align: center;
.touch-tight {
width: 24px;
display: flex;
justify-content: center;
}
}
.animate {
animation-duration: 0.15s;
animation-name: jitter;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
}
.touch {
height: 100%;
width: 50px;
}
@keyframes jitter {
0% {
transform: rotate(3deg);
}
50% {
transform: rotate(0deg);
}
100% {
transform: rotate(-3deg);
}
}
</style>
版权声明:本文为weixin_44766849原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。