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 相关文章推荐
ext combox 下拉框不出现自动提示,自动选中的解决方法
Feb 24 Javascript
30个最佳jQuery Lightbox效果插件分享
Apr 11 Javascript
JavaScript高级程序设计 阅读笔记(二十) js错误处理
Aug 14 Javascript
JavaScript实现添加、查找、删除元素
Jul 02 Javascript
浅谈javascript获取元素transform参数
Jul 24 Javascript
jquery 实现输入邮箱时自动补全下拉提示功能
Oct 04 Javascript
JavaScript数据类型学习笔记
Jan 25 Javascript
JavaScript中关联原型链属性特性
Feb 13 Javascript
在原生不支持的旧环境中添加兼容的Object.keys实现方法
Sep 11 Javascript
Node.js中DNS模块学习总结
Feb 28 Javascript
Vue 全局loading组件实例详解
May 29 Javascript
Vue.js组件通信之自定义事件详解
Oct 19 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接口中interface存在的意义
2013/06/27 PHP
ThinkPHP3.1查询语言详解
2014/06/19 PHP
laravel实现上传图片并在页面显示的例子
2019/10/14 PHP
PHP中isset、empty的用法与区别示例详解
2020/11/05 PHP
JS 控制小数位数的实现代码
2011/08/02 Javascript
什么是json和jsonp,jQuery json实例详详细说明
2012/12/11 Javascript
Javascript基础 函数“重载” 详细介绍
2013/10/25 Javascript
JS实现仿苹果底部任务栏菜单效果代码
2015/08/28 Javascript
详解JavaScript基于面向对象之继承
2015/12/13 Javascript
Jquery跨浏览器文本复制插件Zero Clipboard的使用方法
2016/02/28 Javascript
jQuery 如何给Carousel插件添加新的功能
2016/04/18 Javascript
漂亮! js实现颜色渐变效果
2016/08/12 Javascript
Vue 单文件中的数据传递示例
2017/03/21 Javascript
Javascript中Promise的四种常用方法总结
2017/07/14 Javascript
JS计算两个时间相差分钟数的方法示例
2018/01/10 Javascript
vue中在vuex的actions中请求数据实例
2019/11/08 Javascript
[39:19]完美世界DOTA2联赛PWL S2 SZ vs LBZS 第二场 11.26
2020/11/30 DOTA
python进阶教程之动态类型详解
2014/08/30 Python
Python的加密模块md5、sha、crypt使用实例
2014/09/28 Python
python使用ddt过程中遇到的问题及解决方案【推荐】
2018/10/29 Python
解决python测试opencv时imread导致的错误问题
2019/01/26 Python
python创造虚拟环境方法总结
2019/03/04 Python
基于腾讯云服务器部署微信小程序后台服务(Python+Django)
2019/05/08 Python
python实现简单日志记录库glog的使用
2019/12/13 Python
python数据预处理方式 :数据降维
2020/02/24 Python
python 数据分析实现长宽格式的转换
2020/05/18 Python
浅谈pytorch中的BN层的注意事项
2020/06/23 Python
Python3爬虫带上cookie的实例代码
2020/07/28 Python
请假条格式范文
2014/04/10 职场文书
细节决定成败演讲稿
2014/05/12 职场文书
重阳节演讲稿:尊敬帮助老人 弘扬传统美德
2014/09/25 职场文书
2015年留守儿童工作总结
2015/05/22 职场文书
新娘婚礼答谢词
2015/09/29 职场文书
2016年庆“七一”主题党日活动总结
2016/04/05 职场文书
JavaScript 语句之常用 for 循环详解
2021/03/29 Javascript