Bootstrap

微信小程序实现图片拖拽调换位置效果 -- 开箱即用

在编写类似发布朋友圈功能的功能时,需要实现图片的拖拽排序,删除图片等功能。

一、效果展示在这里插入图片描述

**博主的小程序首页也采用了该示例代码,可以在威信中搜索:我的百宝工具箱
在这里插入图片描述

二、示例代码

1.1、在自己的小程序中创建组件
1.2、组件源码
  • wxml代码
    <view class="drag-container">
      <view wx:for="{{dragImgList}}" wx:key="id"
      style="transform: translate({{index === currentIndex ? tranX : item.tranX}}px, {{index === currentIndex ? tranY : item.tranY}}px); z-index: {{index === currentIndex ? 10 : 1}}; width: {{previewSize}}px; height: {{previewSize}}px;" 
      class="drag-item drag-item-transition" 
      mark:index="{{index}}" mark:key="{{item.key}}" 
      catch:longpress="longPress" 
      catch:touchmove="touchMove" 
      catch:touchend="touchEnd">
        <image class="drag-item-img" src="{{item.src}}" mode="aspectFill"/>
        <view catch:tap="deleteImg" mark:key="{{item.key}}" class="drag-item-delete">
          <view class="drag-item-delete_default" style="{{deleteStyle}}">x</view>
        </view>
      </view>
      <view bindtap="uploadImage" class="drag-item drag-upload" hidden="{{dragImgList.length >= maxCount}}" style="transform: translate({{uploadPosition.tranX}}px, {{uploadPosition.tranY}}px); width: {{previewSize}}px; height: {{previewSize}}px;">
        <text>+</text>
      </view>
    </view>
    
  • wxss代码
    .drag-container {
      position: relative;
      left: 30rpx;
      top: 20rpx;
    }
    
    .drag-item {
      position: absolute;
      top: 0;
      left: 0;
    }
    
    .drag-item-transition {
      transition: transform 0.1s
    }
    
    .drag-item-img {
      width: 100%;
      height: 100%;
    }
    
    .drag-item-delete {
      position: absolute;
      top: 0;
      right: 0;
    }
    
    .drag-item-delete_default {
      display: flex;
      width: 21px;
      height: 15px;
      line-height: 10px;
      justify-content: center;
      background-color: rgba(0, 0, 0, 0.7);
      border-radius: 0 0 0 12px;
      color: #FEFEFE;
    }
    
    .drag-upload {
      display: flex;
      justify-content: center;
      align-items: center;
      border: 2px dashed silver;
      width: 100%;
      height: 100%;
      box-sizing: border-box;
      font-size: 70px;
    }
    .drag-upload text{
      margin-top: -20%;
      color: silver;
    }
    
  • js代码
    Component({
      properties: {
        // 每个格子的大小 100*100
        previewSize: {
          type: Number,
          value: 100
        },
        // 默认图片列表
        defaultImgList: {
          type: Array,
          value: [],
          observer(t) {
            if (t?.length && !this.data.dragImgList.length) {
              const e = this.getDragImgList(t);
              this.setUploaPosition(e.length), this.setData({
                dragImgList: e
              })
            }
          }
        },
        // 最大个数
        maxCount: {
          type: Number,
          value: 9
        },
        // 每行列数
        columns: {
          type: Number,
          value: 3
        },
        // 每个格子之间的间隔
        gap: {
          type: Number,
          value: 9
        },
        deleteStyle: {
          type: String,
          value: ""
        }
      },
      data: {
        dragImgList: [],
        containerRes: {
          top: 0,
          left: 0,
          width: 0,
          height: 0
        },
        currentKey: -1,
        currentIndex: -1,
        tranX: 0,
        tranY: 0,
        uploadPosition: {
          tranX: 0,
          tranY: 0
        }
      },
      lifetimes: {
        ready() {
          this.createSelectorQuery().select(".drag-container").boundingClientRect((({
            top: t,
            left: e
          }) => {
            this.setData({
              "containerRes.top": t,
              "containerRes.left": e
            })
          })).exec()
        }
      },
      methods: {
        longPress(t) {
          const e = t.mark.index,
            {
              pageX: a,
              pageY: i
            } = t.touches[0],
            {
              previewSize: s,
              containerRes: {
                top: n,
                left: r
              }
            } = this.data;
          this.setData({
            currentIndex: e,
            tranX: a - s / 2 - r,
            tranY: i - s / 2 - n
          })
        },
        touchMove(t) {
          if (this.data.currentIndex < 0) return;
          const {
            pageX: e,
            pageY: a
          } = t.touches[0], {
            previewSize: i,
            containerRes: {
              top: s,
              left: n
            }
          } = this.data, r = e - i / 2 - n, o = a - i / 2 - s;
          this.setData({
            tranX: r,
            tranY: o
          });
          const h = t.mark.key,
            g = this.getMoveKey(r, o);
          h !== g && this.data.currentKey !== h && (this.data.currentKey = h, this.replace(h, g))
        },
        getMoveKey(t, e) {
          const {
            dragImgList: a,
            previewSize: i,
            columns: s
          } = this.data, n = (t, e) => {
            const a = Math.round(t / i);
            return a >= e ? e - 1 : a < 0 ? 0 : a
          }, r = s * n(e, Math.ceil(a.length / s)) + n(t, s);
          return r >= a.length ? a.length - 1 : r
        },
        replace(t, e) {
          const a = this.data.dragImgList;
          a.forEach((a => {
            t < e ? a.key > t && a.key <= e ? a.key-- : a.key === t && (a.key = e) : t > e && (a.key >= e && a.key < t ? a.key++ : a.key === t && (a.key = e))
          })), this.getListPosition(a)
        },
        getListPosition(t) {
          const {
            previewSize: e,
            columns: a,
            gap: i
          } = this.data, s = t.map((t => (t.tranX = (e + i) * (t.key % a), t.tranY = Math.floor(t.key / a) * (e + i), t)));
          this.setData({
            dragImgList: s
          }), this.updateEvent(s)
        },
        touchEnd() {
          this.setData({
            tranX: 0,
            tranY: 0,
            currentIndex: -1
          }), this.data.currentKey = -1
        },
        updateEvent(t) {
          const e = [...t].sort(((t, e) => t.key - e.key)).map((t => t.src));
          this.triggerEvent("updateImageList", {
            list: e
          })
        },
        async uploadImage() {
          let {
            dragImgList: t,
            maxCount: e
          } = this.data;
          try {
            const a = await wx.chooseMedia({
                count: e - t.length,
                mediaType: ["image"]
              }),
              i = this.getDragImgList(a?.tempFiles?.map((({
                tempFilePath: t
              }) => t)) || [], !1);
            t = t.concat(i), this.setUploaPosition(t.length), this.setData({
              dragImgList: t
            }), this.updateEvent(t)
          } catch (t) {
            console.log(t)
          }
        },
        getContainerRect(t) {
          const {
            columns: e,
            previewSize: a,
            maxCount: i,
            gap: s
          } = this.data, n = t === i ? t : t + 1, r = Math.ceil(n / e);
          return {
            width: e * a + (e - 1) * s,
            height: r * a + s * (r - 1)
          }
        },
        getDragImgList(t, e = !0) {
          let {
            dragImgList: a,
            previewSize: i,
            columns: s,
            gap: n
          } = this.data;
          return t.map(((t, r) => {
            const o = (e ? 0 : a.length) + r;
            return {
              tranX: (i + n) * (o % s),
              tranY: Math.floor(o / s) * (i + n),
              src: t,
              id: o,
              key: o
            }
          }))
        },
        setUploaPosition(t) {
          const {
            previewSize: e,
            columns: a,
            gap: i
          } = this.data, s = {
            tranX: t % a * (e + i),
            tranY: Math.floor(t / a) * (e + i)
          }, {
            width: n,
            height: r
          } = this.getContainerRect(t);
          this.setData({
            uploadPosition: s,
            "containerRes.width": n,
            "containerRes.height": r
          })
        },
        deleteImg(t) {
          const e = t.mark.key,
            a = this.data.dragImgList.filter((t => t.key !== e));
          a.forEach((t => {
            t.key > e && t.key--
          })), this.getListPosition(a), this.setUploaPosition(a.length)
        }
      }
    });
    
  • json代码
    {
      "component": true,
      "usingComponents":{}
    }
    
1.3、在自己的小程序中新建page
1.4、新建page的源码
  • wxml代码
    <view>
    	<wxDragImg
        	defaultImgList="{{imgList}}"
    		previewSize="{{120}}"
    		maxCount="{{9}}"
    		columns="{{3}}"
    		gap="{{10}}"
        	bind:updateImageList="updateImageList">
      </wxDragImg>
    </view>
    
  • js代码
    Page({
      data: {
        imgList: []
      },
      onLoad() {},
      updateImageList(e) {
        console.log(e)
      }
    })
    
  • json代码
    {
      "usingComponents": {
        "wxDragImg": "../wx-drag-img"
      }
    }
    
;