0

0

基于JQuery的列表拖动排序实现代码_jquery

php中文网

php中文网

发布时间:2016-05-16 17:20:54

|

1465人浏览过

|

来源于php中文网

原创

要求

拖动排序,从名字就不难想像,就是按住一行数据拖到想要的排序位置,保存新的排序队列。

思路

首先给列表行建立锚点,绑定mousedown和mouseup事件,当鼠标移动到想要插入的位置时,将对象行移动到目标行,然后对其经过的所有行进行排序处理。

思路很简单,但这里面仍然有几个问题要注意

1、移动到什么位置可以视作要插入到目标行的位置。
2、移动出了顶端和底端时,判断为第一和最后。
3、向上移动和向下移动的处理

解决

关于事件

Javascript里鼠标按下和放开事件为onmousedown,onmouseup,JQuery里是mousedown,mouseup,所以,这里使用mousedown和mouseup

首先,要知道界面有多少行,每一行有多高,因为要判断鼠标的移动距离

复制代码 代码如下:

var tbodyHeight=setting.frame.outerHeight();  //setting.frame,父对象
var lineNum=$("."+setting.dgLine).length;  //setting.dgLine,每一行的classname
var lineHeight=Math.ceil(tbodyHeight/lineNum);

之所有要取lineNum(行数),除了计算行高外,还有个目的是要使用index(),通过序列索引值来进行移动行到目标位置

当mousedown事件触发后,就要开始计算鼠标移动的距离,用于判断该行到底要移动到什么位置

复制代码 代码如下:

dgid=$(this).attr(setting.id);  //移动行的ID,setting.id,是每一行用来标记ID的名称
thisIndex=$("#"+setting.linePre+dgid).index(); //该行的索引,setting.linePre,每一行ID关辍
thisLineTop=$("#"+setting.linePre+dgid).offset().top; //该行的top值
topDistance=thisIndex*lineHeight;  //该行距离第一行顶端的距离
downDistance=(lineNum-thisIndex-1)*lineHeight; //该行距离最后一行底端的距离


dgid主要是用来区分每一行的标识,一般的列表都是程序循环输出来的,如果没有这样一个ID,就分不出哪行是哪行,所以,在HTML上,需要定义一个存放ID的家伙。程序通过attr就是来取这个值,保证每一行都有自己唯一的值。

thisLineTop,主要是用来和鼠标移动位置进行高度计算,然后根据行高、索引值来判断是移动到哪一行了。还有个作用是用来确定是否按在了移动锚点上,如果有值,说明是,那后面的mouseup就是成立的,如果没有值,说明没有按到锚点上,mouseup不执行任何操作。为什么要这样做呢?因为不管在页面的什么位置点鼠标,都会触发mouseup事件,如果没有一个判断,就会不停的执行,那就会产生一些问题。

topDistance和downDistance,用来判断鼠标有没有移出列表的范围,如果移除了,也就是鼠标移动的距离大于topDistance或downDistance,那就可以判断为需要移动到第一行或最后一行。

mousedown事件主要做的,就是这几件事情,当然,为了效果,还可以增加一些东西

复制代码 代码如下:

$("#"+setting.linePre+dgid).css('background',setting.lineHighlight); //高亮移动行
var left=e.pageX+20;
var top=e.pageY;
dg_tips(left,top);  //创建一个提示层
$('body').css('cursor','move'); //更改页面的鼠标手势
$("body").disableSelection(); //禁止按下鼠标后移动鼠标时选中页面元素
setting.frame.mousemove(function(e){  //让提示层跟随鼠标移动
$("#dgf").css({"left":e.pageX+setting.tipsOffsetLeft+'px',"top":e.pageY+'px'});
});

这些的目的,只是让操作起来更有效果,比如高亮行,就是要让用户知道,他们操作的是哪一行。提示层的作用也一样。

关于禁止选中,.disableSelection();这是jQuery_UI里带的方法,如果你有使用jQuery_UI,那可以直接使用它,如果没有使用,可以这样做

复制代码 代码如下:

$('body').each(function() {          
 $(this).attr('unselectable', 'on').css({
  '-moz-user-select':'none',
  '-webkit-user-select':'none',
  'user-select':'none'
 }).each(function() {
  this.onselectstart = function() { return false; };
 });
});

取消禁止选择

青柚面试
青柚面试

简单好用的日语面试辅助工具

下载

复制代码 代码如下:

$('body').each(function() {          
 $(this).attr('unselectable', '').css({
  '-moz-user-select':'',
  '-webkit-user-select':'',
  'user-select':''
 });
});

考虑到通用性,所以后面的代码里,不会使用.disableSelection();

好了,下面是mouseup事件。这里mouseup事件是绑定在body上的,因为mouseup如果只是绑定在锚点上,那当鼠标移出锚点的时候,再松开鼠标,会发现,这个mouseup事件不执行了,因为它会认为是别的对象的mouseup。所以,最保险的方法是用$('body').mouseup。这样基本上就不会有问题。

mouseup触发后,首先就要判断thisLineTop是不是有值,防止无意义的事件执行。跟着判断鼠标移动的距离是正还是负,也就是向上移动还是向下移动。

var moveDistance=e.pageY-thisLineTop;

根据不同的方向作不同的处理

复制代码 代码如下:

if(moveDistance if(thisIndex!=0){
  moveDistance=Math.abs(moveDistance);  //为负数的时候,取一下绝对值
  if(moveDistance>lineHeight/2){ //判断移动距离是否超过行高的1/2
   if(moveDistance>topDistance){ //如果移动距离大于该行到顶边的距离
    focusIndex=0;
   }else{
    focusIndex=thisIndex-Math.ceil(moveDistance/lineHeight);
   }
   $("."+setting.dgLine).eq(focusIndex).before($("#"+setting.linePre+dgid));//将该行插入目标位置
  }
 }
}else{
 if(thisIndex!=lineNum-1){
  if(moveDistance>lineHeight/2+lineHeight){
   if(moveDistance>downDistance){
    focusIndex=lineNum-1;
   }else{
    focusIndex=thisIndex+Math.ceil(moveDistance/lineHeight)-1;
   }
   $("."+setting.dgLine).eq(focusIndex).after($("#"+setting.linePre+dgid));
  }
 }
}

之所以判断移动距离是否超过行高的1/2,是因为如果只移动一小点,可以视作不移动。在计算目标索引值的时候,使用了Math.ceil,最进位,而当移动距离大于0的时候,取了进位还要-1,因为是向下嘛。

向上移动和向下移动使用了不同的插入方法,before和after,可以试着想一下为什么要使用before和after。

移动完了,还得把按下鼠标时使用的效果给去除掉

复制代码 代码如下:

$("#dgf").remove();//移除提示层
$("#"+setting.linePre+dgid).css('background','');//将高亮的行变为普通
dgid='';//将移动行的ID值空
thisLineTop=0;//将移动行的Top值至0
$('body').css('cursor','default');//更改鼠标手势为默认

基本上的情况就是这样,主要问题就是在处理移动和判断在哪里插入的问题上。其它的都非常简单。

下面给出完整的封装程序,包括更新数据部分

复制代码 代码如下:

/*
*
*  DragList.js
*  @author fuweiyi

*/
(function($){
 $.fn.DragList=function(setting){
  var _setting = {
   frame : $(this),
   dgLine : 'DLL',
   dgButton : 'DLB',
   id : 'action-id',
   linePre : 'list_',
   lineHighlight : '#ffffcc',
   tipsOpacity : 80,
   tipsOffsetLeft : 20,
   tipsOffsetTop : 0,
   JSONUrl : '',
   JSONData : {},
   maskLoaddingIcon : '',
   maskBackgroundColor : '#999',
   maskOpacity : 30,
   maskColor : '#000',
   maskLoadIcon:'',
  };
  var setting = $.extend(_setting,setting);

  var dgid='',thisIndex,thisLineTop=0,topDistance,downDistance;
  var tbodyHeight=setting.frame.outerHeight();
  var lineNum=$("."+setting.dgLine).length;
  var lineHeight=Math.ceil(tbodyHeight/lineNum);

  $("."+setting.dgButton).mousedown(function(e){
   dgid=$(this).attr(setting.id);
   thisIndex=$("#"+setting.linePre+dgid).index();
   var left=e.pageX+20;
   var top=e.pageY;
   thisLineTop=$("#"+setting.linePre+dgid).offset().top;
   topDistance=thisIndex*lineHeight;
   downDistance=(lineNum-thisIndex-1)*lineHeight;
   $("#"+setting.linePre+dgid).css('background',setting.lineHighlight);

   dg_tips(left,top);
   $('body').css('cursor','move');
   unselect();
   setting.frame.mousemove(function(e){
    $("#dgf").css({"left":e.pageX+setting.tipsOffsetLeft+'px',"top":e.pageY+'px'});
   });
  });

  $('body').mouseup(function(e){
   if(thisLineTop>0){
    var moveDistance=e.pageY-thisLineTop;
    if(moveDistance     if(thisIndex!=0){
      moveDistance=Math.abs(moveDistance);
      if(moveDistance>lineHeight/2){
       if(moveDistance>topDistance){
        focusIndex=0;
       }else{
        focusIndex=thisIndex-Math.ceil(moveDistance/lineHeight);
       }
       $("."+setting.dgLine).eq(focusIndex).before($("#"+setting.linePre+dgid));
       dg_update(thisIndex,focusIndex);
      }
     }
    }else{
     if(thisIndex!=lineNum-1){
      if(moveDistance>lineHeight/2+lineHeight){
       if(moveDistance>downDistance){
        focusIndex=lineNum-1;
       }else{
        focusIndex=thisIndex+Math.ceil(moveDistance/lineHeight)-1;
       }
       $("."+setting.dgLine).eq(focusIndex).after($("#"+setting.linePre+dgid));
       dg_update(thisIndex,focusIndex);
      }
     }
    }
    $("#dgf").remove();
    $("#"+setting.linePre+dgid).css('background','');
    dgid='';
    thisLineTop=0;
    $('body').css('cursor','default');
    onselect();
   }
  });

  function dg_update(thisIndex,focusIndex){
   dg_mask();
   var start=thisIndex   var end=thisIndex   var ids='',vals='';
   for(var i=start;i    ids+=i==start?$("."+setting.dgLine).eq(i).attr(setting.id):','+$("."+setting.dgLine).eq(i).attr(setting.id);
    vals+=i==start?i:','+i;
   }
   $.getJSON(setting.JSONUrl,{'do':'changeorders','ids':ids,'vals':vals},function(d){
    $("#dg_mask").remove(); 
   });
  }

  function dg_mask(){
   var W=setting.frame.outerWidth();
   var H=setting.frame.outerHeight();
   var top=setting.frame.offset().top;
   var left=setting.frame.offset().left;
   var mask="

正在使劲的保存...
";
   $('body').append(mask);
   $("#dg_mask").css({"background":"#999","position":'absolute','width':W+'px','height':H+'px','line-height':H+'px','top':top+'px','left':left+'px','filter':'alpha(opacity='+setting.maskOpacity+')','moz-opacity':setting.maskOpacity/100,'opacity':setting.maskOpacity/100,'text-align':'center','color':'#000'});
  }

  function dg_tips(left,top){
   var floatdiv="
移动一条记录
";
   $('body').append(floatdiv);
  }

  function unselect(){
   $('body').each(function() {          
    $(this).attr('unselectable', 'on').css({
     '-moz-user-select':'none',
     '-webkit-user-select':'none',
     'user-select':'none'
    }).each(function() {
     this.onselectstart = function() { return false; };
    });
   });
  }

  function onselect(){
   $('body').each(function() {          
    $(this).attr('unselectable', '').css({
     '-moz-user-select':'',
     '-webkit-user-select':'',
     'user-select':''
    });
   });
  }
 }
})(jQuery);

使用

复制代码 代码如下:


 
  
   
   
  
 
 
  
  
   
   
  
  
 
拖动 名称
@@##@@
这里是一行


参数主要是dgLine,dgButton,id,linePre和JSONUrl,通过看HTML代码,应该不难理解。

关于拖动排序就是这么多了,当然还可以把效果做得更漂亮些,提示更清楚点,有助于用户体验

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
2026春节习俗大全
2026春节习俗大全

本专题整合了2026春节习俗大全,阅读专题下面的文章了解更多详细内容。

68

2026.02.11

Yandex网页版官方入口使用指南_国际版与俄罗斯版访问方法解析
Yandex网页版官方入口使用指南_国际版与俄罗斯版访问方法解析

本专题全面整理了Yandex搜索引擎的官方入口信息,涵盖国际版与俄罗斯版官网访问方式、网页版直达入口及免登录使用说明,帮助用户快速、安全地进入Yandex官网,高效使用其搜索与相关服务。

200

2026.02.11

虫虫漫画网页版入口与免费阅读指南_正版漫画全集在线查看方法
虫虫漫画网页版入口与免费阅读指南_正版漫画全集在线查看方法

本专题系统整理了虫虫漫画官网及网页版最新入口,涵盖免登录观看、正版漫画全集在线阅读方式,并汇总稳定可用的访问渠道,帮助用户快速找到虫虫漫画官方页面,轻松在线阅读各类热门漫画内容。

40

2026.02.11

Docker容器化部署与DevOps实践
Docker容器化部署与DevOps实践

本专题面向后端与运维开发者,系统讲解 Docker 容器化技术在实际项目中的应用。内容涵盖 Docker 镜像构建、容器运行机制、Docker Compose 多服务编排,以及在 DevOps 流程中的持续集成与持续部署实践。通过真实场景演示,帮助开发者实现应用的快速部署、环境一致性与运维自动化。

4

2026.02.11

Rust异步编程与Tokio运行时实战
Rust异步编程与Tokio运行时实战

本专题聚焦 Rust 语言的异步编程模型,深入讲解 async/await 机制与 Tokio 运行时的核心原理。内容包括异步任务调度、Future 执行模型、并发安全、网络 IO 编程以及高并发场景下的性能优化。通过实战示例,帮助开发者使用 Rust 构建高性能、低延迟的后端服务与网络应用。

1

2026.02.11

Spring Boot企业级开发与MyBatis Plus实战
Spring Boot企业级开发与MyBatis Plus实战

本专题面向 Java 后端开发者,系统讲解如何基于 Spring Boot 与 MyBatis Plus 构建高效、规范的企业级应用。内容涵盖项目架构设计、数据访问层封装、通用 CRUD 实现、分页与条件查询、代码生成器以及常见性能优化方案。通过完整实战案例,帮助开发者提升后端开发效率,减少重复代码,快速交付稳定可维护的业务系统。

6

2026.02.11

包子漫画网页版入口与全集阅读指南_正版免费漫画快速访问方法
包子漫画网页版入口与全集阅读指南_正版免费漫画快速访问方法

本专题汇总了包子漫画官网和网页版入口,提供最新章节抢先看方法、正版免费阅读指南,以及稳定访问方式,帮助用户快速直达包子漫画页面,无广告畅享全集漫画内容。

159

2026.02.10

MC.JS网页版快速畅玩指南_MC.JS官网在线入口及免安装体验方法
MC.JS网页版快速畅玩指南_MC.JS官网在线入口及免安装体验方法

本专题汇总了MC.JS官网入口和网页版快速畅玩方法,提供免安装访问、不同版本(1.8.8、1.12.8)在线体验指南,以及正版网页端操作说明,帮助玩家轻松进入MC.JS世界,实现即时畅玩与高效体验。

89

2026.02.10

谷歌邮箱网页版登录与注册全指南_Gmail账号快速访问与安全操作教程
谷歌邮箱网页版登录与注册全指南_Gmail账号快速访问与安全操作教程

本专题汇总了谷歌邮箱网页版的最新登录入口和注册方法,详细提供官方账号快速访问方式、网页版操作教程及安全登录技巧,帮助用户轻松管理Gmail邮箱账户,实现高效、安全的邮箱使用体验。

78

2026.02.10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
jQuery 教程
jQuery 教程

共42课时 | 5.9万人学习

HTML+CSS基础与实战
HTML+CSS基础与实战

共132课时 | 10.8万人学习

tp6+adminlte搭建通用后台
tp6+adminlte搭建通用后台

共39课时 | 5.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号