JavaScript 实现鼠标拖动元素实例代码


Posted in Javascript onFebruary 24, 2014

一、前言

最开始实现鼠标拖动元素的目的就是在一个页面上拖动很多小圆点,用于固定定位,然后在复制HTML,粘贴在页面的开发代码中,就是这么一个功能,实现了很多遍,都没有做好,不得已采用了jQuery.fn.draggable插件,在接触一些资料和别人的思路,今天终于把这个拖动功能给完善了,下面就来看看它的实现

 
二、设计思路

在拖动元素上绑定鼠标按下事件,在文档对象中绑定鼠标移动,鼠标弹起事件;
为什么不把三个事件都绑定在拖动元素上,这是因为鼠标移动太快时,鼠标移动和弹起事件处理程序将不会执行

$target.bind('mousedown', fn);
$(document)
.bind('mousemove', fn)
.bind('mouseup', fn);

三、源码实现细节

在实现源码中有很多需要值得注意的地方:

1、首先在鼠标按下事件中,当单击拖动元素中,可能会选择区域文字,这并不是我们所需要的,解决方法如下:

// 阻止区域文字被选中 for chrome firefox ie9
e.preventDefault();
// for firefox ie9 || less than ie9
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();

2、如果拖动元素是图片(img标签),鼠标在拖动图片一小段距离,会出现一个禁止的小提示,即:图片不能再拖动,
这是浏览器的默认行为,因此只要阻止浏览器默认行为就可以了

e.preventDefault();

3、关于边界(处理拖动范围)的问题

一开始实现的代码如下:

// x,y代表拖动元素将要设置的left,top值,limitObj为拖动区域范围对象,测试时就发现问题,
// 在拖动过程中,拖动对象有时不能直接靠近边界
if ( x >= limitObj._left && x <= limitObj._right ) {
    $target.css({ left: x + 'px' });
}
if ( y >= limitObj._top && y <= limitObj._bottom ) {
    $target.css({ top: y + 'px' });
}

进一步思考:为什么会出现上面问题,原因在于变量x可能会小于limitObj._left或大于limitObj._right,变量y同理,
因此代码需要像下面这样处理:

if (x < limitObj._left) {
    x = limitObj._left;
}
if (x > limitObj._right) {
    x = limitObj._right;
}
if (y < limitObj._top) {
    y = limitObj._top;
}
if (y > limitObj._bottom) {
    y = limitObj._bottom;
}
$target.css({ left: x + 'px', top: y + 'px' });

终于解决了这个问题,但是cloudgamer给出了更好的写法:

$target.css({
    left: Math.max( Math.min(x, limitObj._right),  limitObj._left) + 'px',
    top: Math.max( Math.min(y, limitObj._bottom),  limitObj._top) + 'px'
});

完整程序源码:

$.fn.extend({
    /**
     *   Autor: 博客园华子yjh 2014/02/21
     */
    drag: function(options) {
        var dragStart, dragMove, dragEnd,
            $boundaryElem, limitObj;
        function _initOptions() {
            var noop = function(){}, defaultOptions;
            defaultOptions = { // 默认配置项
                boundaryElem: 'body' // 边界容器
            };
            options = $.extend( defaultOptions, options || {} );
            $boundaryElem = $(options.boundaryElem);
            dragStart = options.dragStart || noop,
            dragMove = options.dragMove || noop,
            dragEnd = options.dragEnd || noop;
        }
        function _drag(e) {
            var clientX, clientY, offsetLeft, offsetTop,
                $target = $(this), self = this;
            limitObj = {
                _left: 0,
                _top: 0,
                _right: ($boundaryElem.innerWidth() || $(window).width()) - $target.outerWidth(),
                _bottom: ($boundaryElem.innerHeight() || $(window).height()) - $target.outerHeight()
            };
            // 记录鼠标按下时的位置及拖动元素的相对位置
            clientX = e.clientX;
            clientY = e.clientY;
            offsetLeft = this.offsetLeft;
            offsetTop = this.offsetTop;
            dragStart.apply(this, arguments);
            $(document).bind('mousemove', moveHandle)
                        .bind('mouseup', upHandle);
            // 鼠标移动事件处理
            function moveHandle(e) {
                var x = e.clientX - clientX + offsetLeft;
                var y = e.clientY - clientY + offsetTop;
                $target.css({
                    left: Math.max( Math.min(x, limitObj._right),  limitObj._left) + 'px',
                    top: Math.max( Math.min(y, limitObj._bottom),  limitObj._top) + 'px'
                });
                dragMove.apply(self, arguments);
                // 阻止浏览器默认行为(鼠标在拖动图片一小段距离,会出现一个禁止的小提示,即:图片不能再拖动)
                e.preventDefault();
            }
            // 鼠标弹起事件处理
            function upHandle(e) {
                $(document).unbind('mousemove', moveHandle);
                dragEnd.apply(self, arguments);
            }
        }
        _initOptions(); // 初始化配置对象
        $(this)
        .css({ position: 'absolute' })
        .each(function(){
            $(this).bind('mousedown', function(e){
                _drag.apply(this, [e]);
                // 阻止区域文字被选中 for chrome firefox ie9
                e.preventDefault();
                // for firefox ie9 || less than ie9
                window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
            });
        });
        return this;
    }
});

实例调用:

// 调用实例
(function(){
    $('.drag-elem').drag({
        boundaryElem: '#boundary',
        dragStart: function(){
            $(this).html('<span>准备拖动</span>').css({ zIndex: 2 }).siblings().css({ zIndex: 1 });
        },
        dragMove: function(){
            var pos = $(this).position();
            $(this).html('<span>拖动中(' +  pos.left + ',' + pos.top + ')</span>' );
        },
        dragEnd : function(){
            $(this).html('<span>拖动结束</span>');            
        }
    });
}());
Javascript 相关文章推荐
javascript YUI 读码日记之 YAHOO.util.Dom - Part.4
Mar 22 Javascript
vs2003 js文件编码问题的解决方法
Mar 20 Javascript
基于jQuery的Tab选项框效果代码(插件)
Mar 01 Javascript
js调用css属性写法
Sep 21 Javascript
js实现Select下拉框具有输入功能的方法
Feb 06 Javascript
JavaScript父子窗体间的调用方法
Mar 31 Javascript
简介AngularJS的视图功能应用
Jun 17 Javascript
iScroll.js 使用方法参考
May 16 Javascript
javascript 删除数组元素和清空数组的简单方法
Feb 24 Javascript
详解Vue快速零配置的打包工具——parcel
Jan 16 Javascript
Vue实现购物车实例代码两则
May 30 Javascript
JS数组方法some、every和find的使用详情
Oct 05 Javascript
对table和ul实现js分页示例分享
Feb 24 #Javascript
jquery.post用法之type设置问题
Feb 24 #Javascript
jQuery获得IE版本不准确webbrowser的解决方法
Feb 23 #Javascript
js获得页面的高度和宽度的方法
Feb 23 #Javascript
使用js判断当前时区TimeZone是否是夏令时
Feb 23 #Javascript
js获得当前时区夏令时发生和终止的时间代码
Feb 23 #Javascript
js 金额格式化来回转换示例
Feb 23 #Javascript
You might like
图象函数中的中文显示
2006/10/09 PHP
用Php编写注册后Email激活验证的实例代码
2013/03/11 PHP
PHP获取文件行数的方法
2015/06/10 PHP
Laravel+jQuery实现AJAX分页效果
2016/09/14 PHP
php使用preg_match()函数验证ip地址的方法
2017/01/07 PHP
PHP基于socket实现的简单客户端和服务端通讯功能示例
2017/07/10 PHP
thinkPHP3.2.2框架行为扩展及demo示例
2018/06/19 PHP
学习jquery必备 api中英文对照的chm手册 下载
2007/05/03 Javascript
setAttribute 与 class冲突解决
2008/02/17 Javascript
图片轮换效果实现代码(点击按钮停止执行)
2013/04/12 Javascript
JS读取XML文件示例代码
2013/11/15 Javascript
js+css实现tab菜单切换效果的方法
2015/01/20 Javascript
Bootstrap零基础入门教程(二)
2016/07/18 Javascript
Bootstrap源码解读模态弹出框(11)
2016/12/28 Javascript
jquery 手势密码插件
2017/03/17 Javascript
js脚本编写简单刷票投票系统
2017/06/27 Javascript
浅谈Webpack打包优化技巧
2018/06/12 Javascript
vue-swiper的使用教程
2018/08/30 Javascript
Javascript实现秒表倒计时功能
2018/11/17 Javascript
Python装饰器用法实例总结
2018/02/07 Python
PyTorch读取Cifar数据集并显示图片的实例讲解
2018/07/27 Python
python 通过手机号识别出对应的微信性别(实例代码)
2019/12/22 Python
Python魔术方法专题
2020/06/19 Python
python爬虫beautifulsoup库使用操作教程全解(python爬虫基础入门)
2021/02/19 Python
检测浏览器对HTML5和CSS3支持度的方法
2015/06/25 HTML / CSS
会计实习自我鉴定
2013/12/04 职场文书
战友聚会主持词
2014/04/02 职场文书
公务员诚信承诺书
2014/05/26 职场文书
卖车协议书范本4篇
2014/10/01 职场文书
个人纪律作风整改措施思想汇报
2014/10/12 职场文书
2014年内部审计工作总结
2014/12/09 职场文书
2016年党员干部公开承诺书
2016/03/24 职场文书
晶体管单管来复再生式收音机
2021/04/22 无线电
Go语言中break label与goto label的区别
2021/04/28 Golang
Python 解决空列表.append() 输出为None的问题
2021/05/23 Python
关于SpringBoot 使用 Redis 分布式锁解决并发问题
2021/11/17 Redis