【記錄】微信小程序實現九宮格圖片拖拽

前陣子有個需求是實現圖片拖拽排序的問題,那會剛接觸微信小程序,搗鼓了不少久,也查了不少資料,不過仍是不少混亂的地方,最後實現了,因此在此記錄一下,但願能幫到其餘人,若是有寫的不對,或者能夠改進的地方,能夠告訴我一聲,謝謝你們。node

效果圖

(在真機上的效果就不演示了,是差很少的)

實現思路

佈局

在這裏運用到了微信小程序的moveable-areamoveable-view兩個標籤。git

moveable-area是可拖拽的區域,須要設置其寬高。因爲圖片的大小我是根據屏幕來動態設置的,因此moveable-area的寬度是固定的100%,高度由上傳的圖片總高度決定,因此一開始的時候,我設置了最小高度。github

moveable-view的寬高跟圖片一致,也是動態設置,初始狀態是隱藏的,當圖片被長按時纔會顯示。當長按要排序的圖片的時候,記錄它的url,並賦值給moveable-view的image。小程序

<movable-area class="movable-area" style="min-height:{{imageWitdh}}px;height:{{areaHeight}}px">
      <!--圖片上傳-->
      <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>
          <!--圖片上傳按鈕-->
          <view class="add-button" style="width:{{imageWitdh}}px;height:{{imageWitdh}}px" wx:if="{{images.length >= 0 &&images.length < 9}}">+</view>
          <!--確保flex佈局justify-content:space-between最後一行左對齊-->
          <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>
複製代碼

頁面初始化時計算寬高的js微信小程序

// 計算圖片寬度
_handleComputedImage:function(e){
    const windowWidth = app.globalData.systemInfo.windowWidth;
    const width = windowWidth - 16;
    const imageWitdh = (width - 16) / 3;
    this.setData({
      imageWitdh
    })
},
複製代碼

上傳圖片

在上傳圖片以後,咱們須要改變moveable-area的高度數組

// 選擇圖片
  handleChooseImage: function (e) {
    let length = this.data.images.length;
    if (length == 9) {
      wx.showToast({
        title: "親,最多隻能選擇九張圖哦~",
        icon: "none",
        duration: 2000
      })
      return false;
    }
    var that = this;
    wx.chooseImage({
      count: 9 - this.data.images.length,
      sizeType: ['compressed'], //可選擇原圖或壓縮後的圖片
      sourceType: ['album', 'camera'], //可選擇性開放訪問相冊、相機
      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(){
          //上傳完以後更新面積
          that._handleComputedArea();
        });
        
      },
      fail: err => console.log(err)
    })
  },
複製代碼

更新面積的計算以下,它的高度由.image-choose-container的view決定:bash

// 計算movable-area的高度
  _handleComputedArea:function(e){
    let that = this;
    wx.createSelectorQuery().selectAll('.image-choose-container').boundingClientRect(function (rect) {
      that.setData({
        areaHeight: rect[0].height
      })
    }).exec()
  },
複製代碼

p.s. 當刪除圖片的時候,咱們也須要從新計算moveable-area的高度。微信

長按圖片

圖片能夠拖拽排序的觸發機制是長按。app

  • 在長按的時候,咱們須要計算每張圖片的座標(這裏的座標不是固定的,當你的頁面能夠拖動的時候,座標值是會發生改變)並保存;
  • 記錄當前圖片在圖片數組中的下標、url;
  • 顯示moveable-view,並設置其x、y值,將url賦值給其下的子元素。
// 計算每張圖片的座標
  _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()
  },
複製代碼
// 長按圖片
  handleLongTap:function(e){
    // 計算每張圖片的座標
    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
    })
  },
複製代碼

此時,長按圖片,moveable-view(帶有邊框)將會出如今該圖片之上。佈局

移動圖片

監聽moveable-view的catchtouchmove事件,(不使用bindhtouchmove的緣由是由於在圖片移動的過程當中,若是頁面是可滑動的,會致使頁面頁跟着滑動),記錄當前手指在頁面上的位置e.touches[0].pageX和e.touches[0].pageY。 爲了保證手指在移動的過程當中,圖片能跟着手指一塊兒移動,則moveable-view的x距離是手指的e.touches[0].pageX,而y距離則是e.touches[0].pageX - 滾動條的移動距離-image-choose-container這個元素距離頂部的距離。

爲了保證在移動圖片的過程當中,圖片始終能在手指的中間,還將x,y分別減去圖片的寬度。(對比兩圖,鼠標與moveable-view的位置)

// 移動的過程當中
  handleTouchMove:function(e){
    let x = e.touches[0].pageX;
    let y = e.touches[0].pageY;
   // 首先先得到當前image-choose-container距離頂部的距離
    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()
  },
複製代碼
// 監聽滾動
  onPageScroll:function(e){
    this.data.scrollTop = e.scrollTop;
  }
複製代碼

中止拖拽時

監聽moveable-view的bindtouchend事件,計算出當前的x,y值,對比每一個圖片的下標,得出它移動到哪一個位置,更新數組,完畢。

// 移動結束的時候
  handleTouchEnd:function(e){
    if (!this.data.flag) {
      // 非長按狀況下
      return;
    }
    let  x = e.changedTouches[0].pageX;
    let y = e.changedTouches[0].pageY - this.data.scrollTop;
    // 每張圖片的地址
    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;
        //臨時保存移動的目標數據
        let temp = data[beginIndex];
        //將移動目標的下標值替換爲被移動目標的下標值
        data[beginIndex] = data[endIndex];
        //將被移動目標的下標值替換爲beginIndex
        data[endIndex] = temp;
      }
    }
    this.setData({
      images: data,
      hidden: true,
      flag: false,
      currentImg: ''
    })
  },
複製代碼

最後附上demo地址: github.com/Middletwo-K…

相關文章
相關標籤/搜索