看一个简单的小程序拖拽排序:

思路分析

首先视图层我们用的是view,因为这个没有兼容问题。看网上拖动排序的demo,大多是绑定movestart,move,moveend事件,维护一个x,y,current变量,通过current在视图层中的wx:for找到当前正在移动的元素,将后利用current==item.id,给它一个moving的class,其中这个moving的class是absolute定位,给所有元素设置left和top,但是只有absolute才会起作用。网上的这种方式可以实现,只不过有一些问题,就是一旦一个元素变成absolute定位,那么之前的位置就会产生空缺,被后面的元素给挤上去。

我们这里为了避免上述方案的问题,从一开始就采用absolute布局,然后利用屏幕的宽度,计算出所有元素的位置,通过left,top纪录当前元素的位置,同时保存_left,_top,因为当一个元素移动的时候left,top改变,当它遇到另外一个元素的时候,通过交换_left,_top信息,可以到那个元素的位置。

首先我们要根据屏幕的宽度来确定每个view的位置,绘制过程大致如下:

关键绘制代码如下:

onLoad: function () {
    var self=this;
    wx.getSystemInfo({
        success: function (res) {
            var width = self.data.all_width=res.windowWidth,_w=0,row=0,column=0;
            var arr=[].concat(self.data.all_list)
            arr.forEach(function(n,i){
                n.left = (self.data.u_w + self.data.s_h) * row + self.data.s_h;
                n.top = (self.data.u_h + self.data.s_v) * column + self.data.s_v;
                n._left = n.left;
                n._top = n.top;
                _w += self.data.u_w+self.data.s_h;
                if (_w+self.data.u_w+self.data.s_h > width){
                    _w=0;
                    row=0;
                    column++;
                }else{
                    row++;
                }
            });
            console.log(arr);
            self.setData({
                all_list: arr
            })
        }
    });
}

绘制完之后就会movestart,move,moveend事件处理了,这里我们拿moveend看看:当停止移动后,我们需要计算出现在停止在那么个模块上了,得到之后拿当前元素和它交换就好了。因为我们的所有模块大小都是相同的,因此就算出来还是比较简单的,大致就是先算出这个是属于哪一行哪一列的就好了,不过需要排除那些不在模块上的位置。

getCurrnetUnderIndex:function(endx,endy){//获取当前移动下方index
    var endx = x2 + this.data.u_w / 2,
        endy = y2 + this.data.u_h / 2;
    var v_judge=false,h_judge=false,column_num=(this.data.all_width-this.data.s_h)/(this.data.s_h+this.data.u_w)>>0;
    // console.log(endx,endy);
    var _column = (endy - this.data.s_v) / (this.data.u_h + this.data.s_v) >> 0;
    var min_top = this.data.s_v + (_column) * (this.data.u_h + this.data.s_v),
    max_top = min_top + this.data.u_h;
    // console.log('v', _column, endy, min_top, max_top);
    if (endy > min_top && endy < max_top) {
        v_judge=true;
    }
    var _row = (endx - this.data.s_h) / (this.data.u_w + this.data.s_h) >> 0;
    var min_left = this.data.s_h + (_row) * (this.data.u_w + this.data.s_h),
        max_left = min_left + this.data.u_w;
    // console.log('x', _row, endx, min_left, max_left);
    if (endx > min_left && endx < max_left) {
        h_judge=true;
    }
    if(v_judge&&h_judge){
        var index = _column * column_num + _row;
        if(index>this.data.all_list.length-1){//超过了
            return null;
        }else{
            return index;
        }
    }else{
        return null;
    }
},

我们可以把这个计算同步到move事件上,就是移动的同时计算下面的模块,如有有就交换,这个比moveend稍微复杂一点,就是交换了之后要马上更新current。

自定义每行个数

现实中的模块大部分是一行占有几个的那种,这是就需要设置一个每行有几个模块:

data: {
    all_list: [{ id: 1, text: '推荐' }, { id: 2, text: 'logo设计' }, { id: 3, text: 'ui设计' }, { id: 4, text: 'css设计' }, { id: 5, text: 'js设计' }, { id: 6, text: '装修设计' }, { id: 4, text: 'css设计' }, { id: 5, text: 'js设计' }, { id: 6, text: '装修设计' }, { id: 4, text: 'css设计' }, { id: 5, text: 'js设计' }, { id: 6, text: '装修设计' }],//已经增加的列表
    current:-1,
    s_v:10,
    s_h:10,
    u_w:0,//这个由num控制,num表示一行几个
    u_h:120,
    num:3,//每行显示几个
    speed: 1.5,//>1,交换的速度
    all_width:'',//总的宽度
    move_x:'',
    move_y:''
},

在data中增加了num和speed配置,num表示一行有几个模块,这样的话,u_w的是这就没用了,因为它是动态计算出来的,计算过程如下:

self.setData({
    u_w: (res.windowWidth-self.data.s_h*(self.data.num+1))/self.data.num
})

计算过程也很简单,比如一个屏幕上等分的展现三个模块,那么每个模块宽度u_w=(allWidth - 4*s_h)/3,示意图如下:

根据速度交换

之前的交换有个问题就是交换的太敏感,例如下图中1和6交换的换,很容易就触碰和旁边的2,3,4,5交换,这样就会越来越麻烦,本来只想换一个,现在换的越来越多。

spped参数是用来检测用户的移动速度,它的计算逻辑是移动的时候,计算当前位置和上一次位置的距离:

Math.sqrt((_x - lastX) * (_x - lastX) + (_y - lastY) * (_y - lastY)) < this.data.speed

如果移动的速度小于设定的,那么我们才会发生交换:

if (underIndex != null && underIndex != this.data.current && (Math.sqrt((_x - lastX) * (_x - lastX) + (_y - lastY) * (_y - lastY)) < this.data.speed)) {
    var arr = [].concat(this.data.all_list);
    this.changeArrayData(arr, underIndex, this.data.current);
    this.setData({
        all_list: arr,
        current: underIndex
    })
}

spped最小为1,如果设置为1,那么无论如何移动都不会交换,默认设置了1.5,表示如果速度比较快的时候,不会发生交换,如果速度比较慢,才会发生交换,这个也可以自己调整。

DEMO下载

点击下载 [0积分]一共下载0
回到顶部
我要评论

所有评论

返回
邮箱:
绑定
取消
×

我要评论

回复:

昵称:(昵称不超过20个字)

图片:

邮箱:
绑定邮箱后,若有回复,会邮件通知。
提交
还可以输入500个字