拖动插件的一些常见问题

最近项目需要,我要实现一个拖动的功能。大概的意思是:你邮箱里面的邮件列表,你可以通过鼠标mousedown后,通过鼠标移动mousemove,把特定的邮件拖动到垃圾箱啊或者草稿箱啊,如果拖动到的地方不是像垃圾箱或草稿箱的元素,就不做处理。

这个功能在邮箱项目上是很普遍的,我稍微看了下我们公司的标准邮箱的实现方法,其中有一个疑问是:为什么不用节流的方式来控制mousemove的操作。大家都知道像mousemove和scroll这种事件,你拖动一下,就可能触发很多次,导致回调方法也执行很多次,性能不好,如果加上函数节流的这种机制,不是可以性能优化吗?这个问题,后面会有详细的解释。

下图就是需要实现的功能截图:

知道了项目的需求,我就开始写代码实现了。

第一点:你必须绑定邮件列表的mousedown事件。由于邮件数目比较多,你不可能给每一封邮件都绑定mousedown事件,这样会影响性能。因此,连初学者都知道要绑定邮件列表的父元素,这样你点击某一封邮件的时候,事件会冒泡到父元素,父元素就会收到这个事件,然后触发事件回调函数,在事件回调函数里面,通过event.target,我们就可以知道用户点击了那一封邮件,进而再处理。这就是所谓的事件委托机制。如果想对事件机制有更深的了解,请看:http://www.cnblogs.com/chaojidan/p/4167675.html。

因此,具体的实现细节如下:

$("div.mailList").on("mousedown",function(event){      .......}

给邮件列表的父元素div绑定mousedown事件,大家都知道jQuery绑定事件有很多种方式,但是我推荐使用on方法,理由有两点:1.有些绑定方法在内部其实就是调用on方法进行事件绑定的。2.on方法绑定事件,兼容性好,而且后面添加的元素也不会出问题(有些绑定方法,当元素是后面添加的时候,绑定就失效了)。如果需要更详细的了解,请自行百度。

第二点:绑定好了mousedown事件后,就要绑定mousemove事件,那这个事件绑定在哪里呢?大家可以想想看,你拖动此邮件元素的时候,是不是在整个页面都应该触发mousemove事件呢,因此,我们需要这样绑定mousemove事件:

$(document).on("mousemove", function(event){
    ........
}

然后,我们就在这个回调函数里面,通过event.target就可以得到鼠标拖动的地方的元素节点。我们通过判断这个元素节点,就可以知道邮件是否可以拖动到这个地方。

第三点:绑定完mousedown事件后,我们就要绑定mouseup事件了,此事件理所当然也是绑定在document上。

$(document).on("mouseup",function(event){   .......}

在此回调函数中,我们就可以通过上面mousemove的回调方法中的判断,是否进行ajax请求。如果鼠标拖动的地方可以接收邮件,那么就进行ajax请求,如果不行,就不用进行ajax请求。

然后,还需要在此回调函数中,取消事件的绑定:

$(document).off("mousemove");
$(document).off("mouseup");

至此,整个的框架就已经出来了。

$("div.mailList").on("mousedown",function(event){      .......
  $(document).on("mousemove", function(event){
      ........
  }
  $(document).on("mouseup",function(event){    ......
    $(document).off("mousemove");
    $(document).off("mouseup");
  }
}

弄完这些之后,基本的功能实现了。

深入进去,你就会发现以下几个问题:

第一个问题:当你点击邮件元素,进行移动的时候,会让其他的文本元素变成蓝色的,这是浏览器的默认风格。但是通过,event.preventDefault()方式,只能解决chrome浏览器,但是火狐,IE下,还是不行。因此,百度得到以下方法:

$("body,html").css({     //解决鼠标拖动时,不会让其他元素变成蓝色
            "-moz-user-select": "none",
            "-khtml-user-select": "none",
            "user-select": "none"
});

当鼠标mousedown时,在回调函数中执行上面的代码。

当鼠标mouseup时,在回调函数中执行下面的代码:

$("body,html").css({
                "-moz-user-select": "auto",
                "-khtml-user-select": "auto",
                "user-select": "auto"
});

问题解决。

第二个问题:当我们拖动元素的时候,需要实时的显示一个div元素,这个div元素会提示我们当前鼠标的地点是否可以接受邮件。因此,我们需要创建一个div元素,由于此div是根据窗口定位的,因此我们只要设置它的position:fixed。

$("<div style=‘border: 1px solid;position:fixed;display:none‘>");

然后,把此元素添加到页面上去。(这里我之前用$(document).append()方法添加此元素,但是一直都添加不上,看jQuery源码,原来只有nodeType=1元素节点或=11文档碎片节点的时候,才能添加元素。而document的nodeType=9。)

$("body").append(divTip);

然后,我们在mousemove的回调函数中,把这个divTip显示出来。

$(divTip).css({
                    "left": x+20,
                    "top": y+20,
                    "z-index" : 99999,
                    "display": "block"
});

其中,x = event.clientX,y = event.clientY。

最后,在mouseup的回调函数中,把这个divTip隐藏。

$(divTip).css({
      "display": "none"
});
$(divTip).remove();

这里,我就要讲一下,如果我们在mousemove的回调函数中使用函数节流的话,那么,就会出现divTip不能实时的跟着鼠标的拖动,移动到鼠标的位置。其实这不是问题,真正的问题是,当你移动到可以接受邮件的元素时,divTip会显示可以接受,这时,你移动鼠标,不小心移到divTip上时,divTip就会显示不可以接受(divTip本身是不能接受邮件的),但过一下,divTip移动后,鼠标就会落在了可以接受邮件的元素上,这时divTip又显示了可以接受。由于你不是实时的,所以divTip就会显示一下不可接受,然后再变成可接受,闪烁的情况会出现。因此,没有用到函数节流。

最后一个问题:如果页面存在iframe的情况,你拖动元素,在iframe下拖动,或者释放鼠标按钮,那么你在document下绑定的mousemove和mouseup就会失效,导致问题出现。当然只有chrome浏览器下没有问题,其他浏览器下都失效了。那如何解决这个问题呢?

我的想法是,在页面上的iframe中绑定mouseup和mousemove事件,然后在mouseup的回调函数中,解绑mouseup和mousemove就行了。

for(var i= 0,len=window.frames.length;i<len;i++){   //其实这里有最简单的方法,就是直接取那个特定的iframe,不用循环去取
            iframes[i]= window.frames[i];
            $(iframes[i].document).on("mouseup",function(event){
                ........
            });
 }

这样绑定后,虽然解决了页面存在iframe时,document绑定mouseup和mousemove失败的问题,但是新的问题出现了,在iframe中你取到的

var x = event.clientX;
var y = event.clientY;

是有问题的,因为iframe在你的页面中存在一定的位移,而此时的event.clientX是相对于iframe来算的,因此你需要加上iframe的位移

var iframeLoc = $("#ueditor_0").offset();

获取iframe元素,调用jQuery的offset方法,就可以搞定了。

然后,你判断,如果用户把邮件拖到iframe中时,你就加上这个iframe的位移:

$(divTip).css({
         "left": x + (iframeLoc ? iframeLoc.left : 0),
         "top": y + (iframeLoc ? iframeLoc.top : 0),
         "z-index" : 99999,
         "display": "block"
});

问题,就解决了。

但是,如果这时,用户拖动了滚动条,这时就会产生滚动的距离,这样上面的计算方法在iframe中就会出错了(这时的event.clientX需要减去滚动距离的scrollLeft)。因此,当在iframe中拖动邮件元素时,我们还需要绑定scroll事件,如果滚动触发,我们就需要减去滚动的位移。

$(document).on("scroll",function(){
        scrollLeft = $(window).scrollLeft();
        scrollTop = $(window).scrollTop();
        isScroll = true;
});

在mousemove时,判断是否在iframe中,如果在iframe中,并且isScroll为true,就必须减去滚动距离(这里,我们通过在iframe的位移中减去scrollLeft,跟在event.clientX减去scrollLeft是一样的效果)。

if(!iframeLoc || isScroll){
         iframeLoc = $("#ueditor_0").offset();
         iframeLoc.left = iframeLoc.left - scrollLeft;
         iframeLoc.top = iframeLoc.top - scrollTop;
         isScroll = false;
}

最终,问题都得到了解决。

当然,上面的拖动插件,我还没有加入ajax请求,也许加入后,会出现更多的问题。这里,我们不讨论ajax请求的情况。

以上只是我简单的看法,大家如果有更好的意见,请评论,我们探讨下。

加油!

时间: 2024-10-27 01:25:00

拖动插件的一些常见问题的相关文章

师父教的拖动插件

建个页面,把jquery 和一个空的js文件导进来赵刚华 21:57:43 空的js文件用来写封装的移动的类 赵刚华 21:58:43 出现这种效果,我们就可以开始了 首页写个类翠 22:03:51 跟上了 赵刚华 22:06:05 定义DragDrop类赵刚华 22:06:21 这个类是封装的专门作移动的类赵刚华 22:07:04 都能理解? 玉子 22:09:21 继续 赵刚华 22:09:57 类都有初始化方法 赵刚华 22:10:03 可以定义一个 翠 22:10:44 类跟对象一样吗

移动端无缝滚动兼拖动插件

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <title>图片点击滑动<

JQuery 左右拖动插件

js文件:http://hokaccha.github.io/js-flipsnap/js/flipsnap.js 官网: http://hokaccha.github.io/js-flipsnap/

dragsort拖动插件的使用

<!DOCTYPE html><html><head> <title>DragSort Example</title> <meta charset="utf-8" /> <style type="text/css"> body { font-family:Arial; font-size:12pt; padding:20px; width:820px; margin:20px aut

jQuery列表拖动排列-jquery list dragsort插件参数和使用方法

在编写网页的时候,有时可能需要对ul的li进行排序,今天就给大家推荐使用jquery插件jquery list dragsort实现列表拖动排序效果. 效果如图: jquery list dragsort列表拖动插件使用方法 $("ul").dragsort({     dragSelector: "li",     dragEnd: function() { },     dragBetween: false,     placeHolderTemplate: &

【转】jQuery列表拖动排列-jquery list dragsort插件参数和使用方法

转自:http://www.itokit.com/2014/0820/75058.html 我们在编辑页面元素排序的时候,我推荐使用jquery插件:dragsort. dragsort官网地址:http://dragsort.codeplex.com/ 在编写网页的时候,有时可能需要对ul的li进行排序,今天就给大家推荐使用jquery插件jquery list dragsort实现列表拖动排序效果. 效果如图: jquery list dragsort列表拖动插件使用方法 $("ul&quo

可以拖动的插件

1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"> 5 <title></title> 6 <link rel="stylesheet" href="左边选项卡/css/bootstrap.min.css"/> 7 8 <style> 9 *{

canvas实现拖动页面时显示窗口视频

简介 当前主流的视频网站目前有不少新鲜好玩的功能,最明显的莫过于小视频的显示--当视频不在当前视口范围 时,会在右下角用一个小窗口来显示当前的视频,而且可以拖拽. 今晚心血来潮,起了动手试试的念头.我的想法很简单,用canvas来获取视频每一帧的数据,并用动画函数 requestAnimationFrame函数(这里没有考虑兼容性)来显示每一帧的视频数据.另外,对canvas绑定拖动的 功能,这样就基本实现了简易的窗口视频. 本章内容的重点就是requestAnimationFrame函数和ca

dragsort拖动排序

引入文件jQuery.jquery.dragsort-0.5.2.min.js html文件: css文件: ul { margin:0px; padding:0px; margin-left:20px; } #uMenuSetting { list-style-type:none; margin:0px; } #uMenuSetting li { float:left; padding:0px;margin-top:5px;} .placeHolder div { background-col