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和ActionScript的交互实现代码
Aug 01 Javascript
浅析LigerUi开发中谨慎载入common.css文件
Jul 09 Javascript
jquery实现的Accordion折叠面板效果代码
Sep 02 Javascript
Bootstrap每天必学之媒体对象
Nov 30 Javascript
js滑动提示效果代码分享
Mar 10 Javascript
jquery实现界面无刷新加载登陆注册
Jul 30 Javascript
微信小程序 保留小数(toFixed)详细介绍
Nov 16 Javascript
node.js 发布订阅模式的实例
Sep 10 Javascript
JavaScript实现单击网页任意位置打开新窗口与关闭窗口的方法
Sep 21 Javascript
jQuery实现监听下拉框选中内容发生改变操作示例
Jul 13 jQuery
解决vue单页路由跳转后scrollTop的问题
Sep 03 Javascript
react组件从搭建脚手架到在npm发布的步骤实现
Jan 09 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
PHP ADODB实现分页功能简单示例
2018/05/25 PHP
浅谈laravel数据库查询返回的数据形式
2019/10/21 PHP
JSQL 基于客户端的成绩统计实现方法
2010/05/05 Javascript
this和执行上下文实现代码
2010/07/01 Javascript
JS 打印界面的CSS居中代码适用所有浏览器
2014/03/19 Javascript
页面刷新时记住滚动条的位置jquery代码
2014/06/17 Javascript
鼠标悬浮停留三秒后自动显示大图js代码
2014/09/09 Javascript
JavaScript中5种调用函数的方法
2015/03/12 Javascript
JS显示下拉列表框内全部元素的方法
2015/03/31 Javascript
在JavaScript中处理字符串之link()方法的使用
2015/06/08 Javascript
jQuery实现两款有动画功能的导航菜单代码
2015/09/16 Javascript
微信小程序 教程之WXML
2016/10/18 Javascript
Bootstrap基本插件学习笔记之轮播幻灯片(23)
2016/12/08 Javascript
利用n 升级工具升级Node.js版本及在mac环境下的坑
2017/02/15 Javascript
js防刷新的倒计时代码 js倒计时代码
2017/09/06 Javascript
抖音上用记事本编写爱心小程序教程
2019/04/17 Javascript
ajaxfileupload.js实现上传文件功能
2019/04/19 Javascript
分享Angular http interceptors 拦截器使用(推荐)
2019/11/10 Javascript
微信小程序开发(一):服务器获取数据列表渲染操作示例
2020/06/01 Javascript
Pyhthon中使用compileall模块编译源文件为pyc文件
2015/04/28 Python
Python实现给文件添加内容及得到文件信息的方法
2015/05/28 Python
使用Python来编写HTTP服务器的超级指南
2016/02/18 Python
基于Django的python验证码(实例讲解)
2017/10/23 Python
处理Selenium3+python3定位鼠标悬停才显示的元素
2019/07/31 Python
python使用sklearn实现决策树的方法示例
2019/09/12 Python
Python如何使用bokeh包和geojson数据绘制地图
2020/03/21 Python
前端面试必备之CSS3的新特性
2017/09/05 HTML / CSS
用CSS禁用输入法(CSS3 UI规范)实例解析
2012/12/04 HTML / CSS
使用phonegap播放音频的实现方法
2017/03/31 HTML / CSS
您的时尚,您的生活方式:DTLR Villa
2019/12/25 全球购物
中学教师请假制度
2014/02/03 职场文书
2014年预备党员学习两会心得体会
2014/03/17 职场文书
环境监测与治理技术专业求职信
2014/07/06 职场文书
中级会计大学生职业生涯规划书
2014/09/16 职场文书
电子银行业务授权委托书
2014/10/10 职场文书
nginx如何将http访问的网站改成https访问
2021/03/31 Servers