[Record] Wechat applet to drag and drop nine palace pictures

Recently, there was a need to achieve drag-and-drop sorting of pictures. It would have just touched the Wechat applet, tampered with it for a long time, and checked a lot of information, but it was still a lot of confusion, and finally achieved. So I want to record here, hoping to help others, if there is something wrong, or can be improved. Please let me know. Thank you.

Design sketch


(The effect on the real machine is not demonstrated, it's almost the same.)

Implementation ideas

layout

Here we use the moveable-area and moveable-view tags of the Wechat applet.

Moeable-area is a draggable area, which needs to be set in width and height. Since the size of the picture is set dynamically according to the screen, the width of moveable-area is fixed at 100%, and the height is determined by the total height of the uploaded image, so I set the minimum height at the beginning.

The width of moveable-view is the same as that of the picture, and it is also set dynamically. The initial state is hidden, and the picture will be displayed when it is pressed for a long time. When the image is long to sort, record its url and assign it to the image of moveable-view.

 <movable-area class="movable-area" style="min-height:{{imageWitdh}}px;height:{{areaHeight}}px">
      <!--Picture upload-->
      <view class="image-choose-container">
        <view class="image-item" style="width:{{imageWitdh}}px;height:{{imageWitdh}}px" wx:for="{{images}}" wx:for-item="url" wx:key="url" data-url="{{url}}" data-index="{{index}}" >
            <image src="{{url}}" mode="aspectFill"></image>
            <view class="close">X</view>
        </view>
          <!--Picture Upload Button-->
          <view class="add-button" style="width:{{imageWitdh}}px;height:{{imageWitdh}}px" wx:if="{{images.length >= 0 &&images.length < 9}}">+</view>
          <!--ensure flex layout justify-content: space-between Left alignment of the last line-->
          <view style="width:{{imageWitdh}}px" class="image-item image-item-temp" wx:if="{{images.length%3==1}}"></view>
      </view>
      
      <movable-view class="movable-view" style="width:{{imageWitdh}}px;height:{{imageWitdh}}px" hidden="{{hidden}}" x="{{x}}" y="{{y}}"  direction="all" damping="{{5000}}" friction="{{1}}">
        <image src="{{currentImg}}" wx:if="{{currentImg.length>0}}"></image>
      </movable-view>
    </movable-area>

Computing width and height js at page initialization

// Calculate picture width
_handleComputedImage:function(e){
    const windowWidth = app.globalData.systemInfo.windowWidth;
    const width = windowWidth - 16;
    const imageWitdh = (width - 16) / 3;
    this.setData({
      imageWitdh
    })
},

Upload pictures

After uploading the image, we need to change the height of moveable-area.

// Select pictures
  handleChooseImage: function (e) {
    let length = this.data.images.length;
    if (length == 9) {
      wx.showToast({
        title: "Pro, you can only choose nine maps at most.~",
        icon: "none",
        duration: 2000
      })
      return false;
    }
    var that = this;
    wx.chooseImage({
      count: 9 - this.data.images.length,
      sizeType: ['compressed'], //Choose the original or compressed image
      sourceType: ['album', 'camera'], //Optional Open Access to Albums, Cameras
      success: res => {
        let images = that.data.images;
        for (let i = 0; i < res.tempFilePaths.length;i++){
          images.push(res.tempFilePaths[i]);
        }
        that.setData({
          images
        },function(){
          //Update area after uploading
          that._handleComputedArea();
        });
        
      },
      fail: err => console.log(err)
    })
  },

The updated area is calculated as follows, and its height is determined by the view of. image-select-container:

// Calculate the height of movable-area
  _handleComputedArea:function(e){
    let that = this;
    wx.createSelectorQuery().selectAll('.image-choose-container').boundingClientRect(function (rect) {
      that.setData({
        areaHeight: rect[0].height
      })
    }).exec()
  },

When deleting pictures, we also need to recalculate the height of moveable-area.

Long press picture

The trigger mechanism for drag-and-drop sorting of images is long press.

  • In the long press, we need to calculate the coordinates of each picture (where the coordinates are not fixed, and when your page can be dragged, the coordinates will change) and save them.
  • Record the subscripts and URLs of the current image in the image array;
  • Display moveable-view, set its x and y values, and assign the url to the child elements below it.
// Calculate the coordinates of each picture
  _handleComputedPoints(e){
    let that = this;
    var query = wx.createSelectorQuery();
    var nodesRef = query.selectAll(".image-item");
    nodesRef.fields({
      dataset: true,
      rect: true
    }, (result) => {
      that.setData({
        pointsArr: result
      })
    }).exec()
  },
 // Long press picture
  handleLongTap:function(e){
    // Calculate the coordinates of each picture
    this._handleComputedPoints();
    this.setData({
      currentImg: e.currentTarget.dataset.url,
      currentIndex: e.currentTarget.dataset.index,
      hidden: false,
      flag: true,
      x: e.currentTarget.offsetLeft,
      y: e.currentTarget.offsetTop
    })
  },

At this point, by pressing the picture long, the moveable-view (with a border) will appear on the picture.

Mobile pictures

Listen for the catchtouch move event of moveable-view. (The reason why bindhtouchmove is not used is that if the page is slidable during image movement, it will cause the page to slide along with it.) Record the current finger position on the page e.touches[0].pageX and e.touches[0].pageY.
In order to ensure that the picture can move with the finger in the process of moving, the x distance of moveable-view is e.touches[0].pageX of the finger, and the y distance is e.touches[0].pageX - moving distance of scrollbar - image-selection-container of the element distance from the top.

In order to ensure that the picture can always be in the middle of the finger in the process of moving the picture, the width of the picture is subtracted by X and Y respectively. (Comparing two pictures, the location of mouse and moveable-view)

  // In the process of moving
  handleTouchMove:function(e){
    let x = e.touches[0].pageX;
    let y = e.touches[0].pageY;
   // Firstly, the distance from the top of the current image-select-container is obtained.
    let that = this;
    wx.createSelectorQuery().selectAll('.image-choose-container').boundingClientRect(function (rect) {
      let top = rect[0].top;
      y = y - that.data.scrollTop - top;
      that.setData({
        x: x - that.data.imageWitdh / 2 > 0 ? x - that.data.imageWitdh / 2:0,
        y: y - that.data.imageWitdh / 2 > 0 ? y - that.data.imageWitdh / 2:0,
      })

    }).exec()
  },
// Monitor rolling
  onPageScroll:function(e){
    this.data.scrollTop = e.scrollTop;
  }

Stop dragging

Listen for the bind touch end event of moveable-view, calculate the current x,y values, compare the subscripts of each picture, find out where it moved, update the array, and finish.

// At the end of the move
  handleTouchEnd:function(e){
    if (!this.data.flag) {
      // Non-long press
      return;
    }
    let  x = e.changedTouches[0].pageX;
    let y = e.changedTouches[0].pageY - this.data.scrollTop;
    // The address of each picture
    const pointsArr = this.data.pointsArr;
    let data = this.data.images;
    for (var j = 0; j < pointsArr.length; j++) {
      const item = pointsArr[j];
      if (x > item.left && x < item.right && y > item.top && y < item.bottom) {
        const endIndex = item.dataset.index;
        const beginIndex = this.data.currentIndex;
        //Temporarily save moving target data
        let temp = data[beginIndex];
        //Replace the subscript value of the moving target with the subscript value of the moving target
        data[beginIndex] = data[endIndex];
        //Replace the subscript value of the moving target with beginIndex
        data[endIndex] = temp;
      }
    }
    this.setData({
      images: data,
      hidden: true,
      flag: false,
      currentImg: ''
    })
  },

Finally, attach demo address:
https://github.com/Middletwo-Kid/wechat-drag-image
The article was first published in:
https://juejin.im/post/5d7cbde06fb9a06b3260a25d

Keywords: Mobile github

Added by nthomthom on Sun, 15 Sep 2019 12:35:07 +0300