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

    思路分析

    首先视图层我们用的是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的位置,绘制过程大致如下:

    关键绘制代码如下:

    1. onLoad: function () {
    2.     var self=this;
    3.     wx.getSystemInfo({
    4.         success: function (res) {
    5.             var width = self.data.all_width=res.windowWidth,_w=0,row=0,column=0;
    6.             var arr=[].concat(self.data.all_list)
    7.             arr.forEach(function(n,i){
    8.                 n.left = (self.data.u_w + self.data.s_h) * row + self.data.s_h;
    9.                 n.top = (self.data.u_h + self.data.s_v) * column + self.data.s_v;
    10.                 n._left = n.left;
    11.                 n._top = n.top;
    12.                 _w += self.data.u_w+self.data.s_h;
    13.                 if (_w+self.data.u_w+self.data.s_h > width){
    14.                     _w=0;
    15.                     row=0;
    16.                     column++;
    17.                 }else{
    18.                     row++;
    19.                 }
    20.             });
    21.             console.log(arr);
    22.             self.setData({
    23.                 all_list: arr
    24.             })
    25.         }
    26.     });
    27. }

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

    1. getCurrnetUnderIndex:function(endx,endy){//获取当前移动下方index
    2.     var endx = x2 + this.data.u_w / 2,
    3.         endy = y2 + this.data.u_h / 2;
    4.     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;
    5.     // console.log(endx,endy);
    6.     var _column = (endy - this.data.s_v) / (this.data.u_h + this.data.s_v) >> 0;
    7.     var min_top = this.data.s_v + (_column) * (this.data.u_h + this.data.s_v),
    8.     max_top = min_top + this.data.u_h;
    9.     // console.log('v', _column, endy, min_top, max_top);
    10.     if (endy > min_top && endy < max_top) {
    11.         v_judge=true;
    12.     }
    13.     var _row = (endx - this.data.s_h) / (this.data.u_w + this.data.s_h) >> 0;
    14.     var min_left = this.data.s_h + (_row) * (this.data.u_w + this.data.s_h),
    15.         max_left = min_left + this.data.u_w;
    16.     // console.log('x', _row, endx, min_left, max_left);
    17.     if (endx > min_left && endx < max_left) {
    18.         h_judge=true;
    19.     }
    20.     if(v_judge&&h_judge){
    21.         var index = _column * column_num + _row;
    22.         if(index>this.data.all_list.length-1){//超过了
    23.             return null;
    24.         }else{
    25.             return index;
    26.         }
    27.     }else{
    28.         return null;
    29.     }
    30. },

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

    自定义每行个数

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

    1. data: {
    2.     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: '装修设计' }],//已经增加的列表
    3.     current:-1,
    4.     s_v:10,
    5.     s_h:10,
    6.     u_w:0,//这个由num控制,num表示一行几个
    7.     u_h:120,
    8.     num:3,//每行显示几个
    9.     speed: 1.5,//>1,交换的速度
    10.     all_width:'',//总的宽度
    11.     move_x:'',
    12.     move_y:''
    13. },

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

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

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

    根据速度交换

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

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

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

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

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

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

    DEMO下载

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

    所有评论

      相关文章