目錄
一、前言與效果展示
二、源碼
1.目錄結(jié)構(gòu)
2.drag.wxml文件
3.drag.wxss文件
(1)drag.less
(2)drag.wxss? 不會使用less的就用這個
4.drag.js文件
5.drag.json文件
三、結(jié)語
一、前言與效果展示
? ? ? ? 最近在做一個賬本,里面有個功能需要“拖拽排序”,網(wǎng)上的代碼我也看不太懂,打算自己寫一個。微信小程序官方給了一個可移動的盒子?movable-view ,基于這個我們來實(shí)現(xiàn)一個簡單的拖拽排序功能
效果: 可以自定義一行展示多少個圖標(biāo),下面演示一行五個的情況
二、源碼
1.目錄結(jié)構(gòu)
我起名為drag,你們可以自己選擇起名
2.drag.wxml文件
(1)使用了wxs定義了parseInt函數(shù) (因?yàn)樵谀0逯胁荒苤苯邮褂胮arseInt(),需要借助wxs)
(2)movable-view中,除了class為showLine的元素不要動,其它的比如icon和name可以自定義樣式刪除或修改 (showLine是用于元素拖拽時的位置提示)
(3)movable-view標(biāo)簽的 style 里,有個background-color,你們可以自己選擇顏色,用于“被拖拽的元素”的背景顏色
<wxs module="m1">
var parseIntNumber = function (num) {
return parseInt(num)
}
module.exports.parseIntNumber = parseIntNumber;
</wxs>
<view class="list">
<movable-area class="moveList" style="height: {{(m1.parseIntNumber(positionList.length/drag.countOneLine)+1) * (drag.height)}}rpx;width: {{drag.outWidth}}rpx;">
<movable-view wx:for="{{positionList}}" wx:key="id" out-of-bounds direction="all" style="height: {{drag.height}}rpx;width: calc({{drag.outWidth}}rpx / {{drag.countOneLine}});background-color: {{nowDragIndex == index ? '#bbbbbb90':''}};" class="moveItem" x="{{positionList[index].left}}rpx" y="{{positionList[index].boxTop}}rpx" bindchange="drag" bindtouchend="dragEnd" data-myindex="{{index}}">
<!-- 藍(lán)色邊邊的出現(xiàn)條件:當(dāng)前輪到index這個索引顯示了 且 當(dāng)前拖動的元素的索引不是index -->
<view class="showLine" wx:if="{{ showLine === index && nowDragIndex!==index}}"></view>
<view class="icon">圖標(biāo)</view>
<view class="name">{{item.name}}</view>
</movable-view>
</movable-area>
</view>
3.drag.wxss文件
我是使用less寫的樣式文件,所以這里會放less 的源代碼,不會使用less 的請看 (2)drag.less
movable-view自動具有絕對定位屬性,只能通過標(biāo)簽里的x和y來定位,無法使用flex布局
(1)drag.less
.list {
display: flex;
flex-wrap: wrap;
.moveList {
width: 100%;
.moveItem {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #ececec00;
.icon {
height: 60rpx;
width: 60rpx;
line-height: 60rpx;
text-align: center;
font-size: 20rpx;
background-color: aqua;
border-radius: 50%;
}
.showLine {
position: absolute;
left: 0;
transform: translate(-50%);
width: 10rpx;
height: 100%;
background-color: blue;
}
}
}
}
(2)drag.wxss? 不會使用less的就用這個
.list {
display: flex;
flex-wrap: wrap;
}
.list .moveList {
width: 100%;
}
.list .moveList .moveItem {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #ececec00;
}
.list .moveList .moveItem .icon {
height: 60rpx;
width: 60rpx;
line-height: 60rpx;
text-align: center;
font-size: 20rpx;
background-color: aqua;
border-radius: 50%;
}
.list .moveList .moveItem .showLine {
position: absolute;
left: 0;
transform: translate(-50%);
width: 10rpx;
height: 100%;
background-color: blue;
}
4.drag.js文件
在data里的drag對象中,可以自定義 盒子的高度、每一行展示的個數(shù)、可移動區(qū)域的寬度
想拖拽排序的數(shù)據(jù)放在 list 里面,注意需要有id,用于wx:for的key值
注:movable-view 的拖拽事件?bindchange 的e.detail中的數(shù)據(jù),單位是px,需要轉(zhuǎn)為rpx才能和我們寫的單位匹配
// pages/drag/drag.js
Page({
/**
* 頁面的初始數(shù)據(jù)
*/
data: {
drag: { //控制拖拽部分的盒子大小,在這里輸入初始數(shù)據(jù)
outWidth: 750, //可移動區(qū)域的寬度,單位rpx,750rpx是屏幕寬度
height: 120, //盒子的高度,單位rpx
countOneLine: 5, //一行盒子的個數(shù),這個決定盒子寬度 (outWidth / countOneLine)
},
list: [ //列表,在這里輸入想展示的數(shù)據(jù),最后將會修改這里的順序
{
id: 0, // id
name: '餐飲', //名稱
},
{
id: 1, // id
name: '交通', //名稱
},
{
id: 2, // id
name: '住房', //名稱
},
{
id: 3, // id
name: '美容', //名稱
},
{
id: 4, // id
name: '服飾', //名稱
},
{
id: 5, // id
name: '運(yùn)動', //名稱
},
{
id: 6, // id
name: '旅行', //名稱
},
{
id: 7, // id
name: '娛樂', //名稱
},
{
id: 8, // id
name: '生活', //名稱
},
{
id: 9, // id
name: '醫(yī)療', //名稱
},
{
id: 10, // id
name: '通訊', //名稱
},
{
id: 11, // id
name: '學(xué)習(xí)', //名稱
},
{
id: 12, // id
name: '禮物', //名稱
},
{
id: 13, // id
name: '親屬', //名稱
},
{
id: 14, // id
name: '數(shù)碼', //名稱
},
{
id: 15, // id
name: '零食', //名稱
},
{
id: 16, // id
name: '購物', //名稱
},
{
id: 17, // id
name: '其它', //名稱
},
{
id: 18, // id
name: '轉(zhuǎn)換', //名稱
},
{
id: 19, // id
name: '出門', //名稱
},
{
id: 20, // id
name: '紅包', //名稱
},
{
id: 21, // id
name: '食堂', //名稱
},
{
id: 22, // id
name: '外賣', //名稱
},
{
id: 23, // id
name: 'AA', //名稱
},
{
id: 24, // id
name: '超市', //名稱
},
{
id: 25, // id
name: '水電', //名稱
},
{
id: 26, // id
name: '早餐', //名稱
},
{
id: 27, // id
name: '水果', //名稱
},
{
id: 28, // id
name: '借款', //名稱
},
],
positionList: [], //把list轉(zhuǎn)化后,具有定位數(shù)據(jù)的列表(展示在頁面上)
//下面的是一些動態(tài)的索引
showLine: -1, //顯示哪個索引的藍(lán)色線
nowDragIndex: -1, //當(dāng)前拖動的索引
},
//拖拽時觸發(fā)
drag(e) {
if (e.detail.source == '') return //如果這個值為空,說明不是手動拖拽的,不要進(jìn)行下面的操作
// console.log(e.detail);
let myindex = e.currentTarget.dataset.myindex //當(dāng)前拖動的圖標(biāo)的index
if (this.data.nowDragIndex !== myindex) { //設(shè)置當(dāng)前拖動的圖標(biāo)
console.log('當(dāng)前拖動的圖標(biāo)序號為', myindex);
this.setData({
nowDragIndex: myindex
})
}
// e.detail單位是px,需要轉(zhuǎn)為rpx
let x = this.pxToRpx(e.detail.x) //轉(zhuǎn)為rpx的x
let y = this.pxToRpx(e.detail.y) //轉(zhuǎn)為rpx的y
let box = {}
let drag = this.data.drag //拖拽部分的變量 寬 高 個數(shù)等
box.leftX = x //正在拖動的盒子的左側(cè)x值
box.rightX = x + drag.outWidth / drag.countOneLine //正在拖動的盒子的右側(cè)x值
box.topY = y //正在拖動的盒子的頂部y值
box.bottomY = y + drag.height //正在拖動的盒子的底部y值
//使用for循環(huán)判斷現(xiàn)在正在哪個位置 - 性能問題,如何防抖?
for (let i = 0; i < this.data.positionList.length; i++) {
const element = this.data.positionList[i];
//判斷拖拽的盒子,在哪個藍(lán)色模塊的位置
if (box.leftX < element.left && box.rightX > element.left && element.boxTop - 20 < box.topY && element.boxBottom + 20 > box.bottomY) {
this.setData({
showLine: i
})
break
}
}
},
//拖拽的結(jié)束,判斷是否應(yīng)該移動,還是回復(fù)原位
dragEnd(e) {
let newIndex = this.data.showLine //即將挪動到的位置
let nowDragIndex = this.data.nowDragIndex //原本的位置
if (newIndex >= 0 && nowDragIndex !== newIndex) { //給showline賦值了且不是自己,說明需要變化位置
console.log('需要變化位置');
let newList = this.data.list //改變的是list,而不是頁面展示的positionList
let item = newList.splice(nowDragIndex, 1) // 刪除指定的元素,給item
newList.splice(newIndex, 0, item[0]) // 把item添加到指定位置
this.setData({
list: newList, //data的list修改,方便接下來重新計算位置
})
//然后刷新頁面,重新計算position
this.countPosition()
} else {
console.log('拖了但沒完全拖,回復(fù)原位');
setTimeout(() => {//使用定時器,防止拖拽到邊緣時,無法正常歸位(等待邊緣動畫結(jié)束后再回復(fù)原位,這個好像是微信小程序這個組件的bug,搜到了三個月前的bug,到現(xiàn)在還沒解決)
this.setData({
positionList: this.data.positionList, //回復(fù)原位
})
}, 300);
}
//重置索引
this.setData({
showLine: -1,
nowDragIndex: -1,
})
console.log(this.data);
},
//計算list里每個數(shù)據(jù)的坐標(biāo),放到positionList里
countPosition() {
let positionList = [] //裝著列表的坐標(biāo)數(shù)據(jù)
let list = this.data.list
for (let i = 0; i < list.length; i++) {
let element = list[i]
positionList.push({
...element,
index: i,
left: (i % this.data.drag.countOneLine) * (this.data.drag.outWidth / this.data.drag.countOneLine),
boxTop: parseInt(i / this.data.drag.countOneLine) * this.data.drag.height,
boxBottom: (parseInt(i / this.data.drag.countOneLine) + 1) * this.data.drag.height,
})
}
this.setData({
positionList
})
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面加載
*/
onLoad(options) {
//#region 定義 px轉(zhuǎn)rpx 函數(shù)
wx.getSystemInfo({
success: (result) => {
this.windowWidth = result.windowWidth
},
})
this.pxToRpx = function (v_px) {
let onePxToRpx = 750 / this.windowWidth
return v_px * onePxToRpx
}
//#endregion
//#region 計算列表的坐標(biāo), 裝著列表的數(shù)據(jù),包含坐標(biāo)
this.countPosition()
//#endregion
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面顯示
*/
onShow() {
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面隱藏
*/
onHide() {
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面卸載
*/
onUnload() {
},
/**
* 頁面相關(guān)事件處理函數(shù)--監(jiān)聽用戶下拉動作
*/
onPullDownRefresh() {
},
/**
* 頁面上拉觸底事件的處理函數(shù)
*/
onReachBottom() {
},
/**
* 用戶點(diǎn)擊右上角分享
*/
onShareAppMessage() {
}
})
5.drag.json文件
無需改動,是默認(rèn)的即可
{
"usingComponents": {}
}
三、結(jié)語
????????本次源碼分享到這里結(jié)束,由于這是我花三個小時寫出來的,肯定存在很多不足,比如在拖拽函數(shù)中,判斷元素應(yīng)該被挪動到的位置,我用了for循環(huán)來一個個判斷,這必定會影響到性能 (因?yàn)槲⑿盘峁┑倪@個拖拽函數(shù),只要盒子稍微移動一點(diǎn)點(diǎn),都會觸發(fā)很多次,再加上里面還有for循環(huán),會造成短時間內(nèi)有多個for循環(huán)在運(yùn)行) 所以建議在數(shù)據(jù)量不大的時候可以使用這個源碼,數(shù)據(jù)量很大的時候會卡頓。
? ? ? ? 除此之外,微信小程序這個組件有個自帶的bug,當(dāng)拖拽到邊緣時,想動態(tài)設(shè)置x和y值,此時x可以被正常設(shè)置,但是y值不可以。就會出現(xiàn):本來拖拽到無效區(qū)域,應(yīng)該跑回原本的位置的,但是x值回去了,y值沒回去,導(dǎo)致這樣。這是頁面顯示效果的問題,不影響排序功能。文章來源:http://www.zghlxwxcb.cn/news/detail-772080.html
????????如果你有更好的解決方式,歡迎在評論區(qū)里不吝賜教!文章來源地址http://www.zghlxwxcb.cn/news/detail-772080.html
到了這里,關(guān)于基于movable-view的微信小程序拖拽排序(含源碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!