用戶
 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

掃一掃,登錄網站

小程序社區 首頁 教程 實戰教程 查看內容

微信小程序實現九宮格圖片拖拽

Rolan 2019-9-18 00:08

前陣子有個需求是實現圖片拖拽排序的問題,那會剛接觸微信小程序,搗鼓了很多久,也查了很多資料,不過還是很多混亂的地方,最后實現了,所以在此記錄一下,希望能幫到其他人,如果有寫的不對,或者可以改進的地方, ...

效果圖

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

實現思路

布局

在這里運用到了微信小程序moveable-areamoveable-view兩個標簽。

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

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決定:

// 計算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的高度。

長按圖片

圖片可以拖拽排序的觸發機制是長按。

  • 在長按的時候,我們需要計算每張圖片的坐標(這里的坐標不是固定的,當你的頁面可以拖動的時候,坐標值是會發生改變)并保存;
  • 記錄當前圖片在圖片數組中的下標、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…

鮮花
鮮花 (1)
雞蛋
雞蛋

剛表態過的朋友 (1 人)

分享至 : QQ空間
收藏
原作者: sugarMei 來自: 掘金
致青春APP