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