uniapp左右拖动换位子

  • Post author:
  • Post category:uniapp


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 版权协议,转载请附上原文出处链接和本声明。