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 grid 添加右击菜单
Nov 26 Javascript
jQuery效果 slideToggle() 方法(在隐藏和显示之间切换)
Jun 28 Javascript
js中window.open打开一个新的页面
Aug 10 Javascript
javascript跨域总结之window.name实现的跨域数据传输
Nov 01 Javascript
javascript编程异常处理实例小结
Nov 30 Javascript
JS使用正则表达式实现关键字替换加粗功能示例
Aug 03 Javascript
vue2.0 中#$emit,$on的使用详解
Jun 07 Javascript
canvas基础绘制-绚丽倒计时的实例
Sep 17 Javascript
详解html-webpack-plugin用法全解
Jan 22 Javascript
node微信开发之获取access_token+自定义菜单
Mar 17 Javascript
深入解读Node.js中的koa源码
Jun 17 Javascript
更优雅的微信小程序骨架屏实现详解
Aug 07 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如何将日志写进syslog
2013/06/28 PHP
PHP实现在线阅读PDF文件的方法
2015/06/17 PHP
PHP Ajax跨域问题解决方案代码实例
2020/08/01 PHP
一个js封装的不错的选项卡效果代码
2008/02/15 Javascript
javascript模仿msgbox提示效果代码
2008/06/10 Javascript
javascript 表格排序和表头浮动效果(扩展SortTable)
2009/04/07 Javascript
AlertBox 弹出层信息提示框效果实现步骤
2010/10/11 Javascript
一个简单的JavaScript数据缓存系统实现代码
2010/10/24 Javascript
Jquery中删除元素的实现代码
2011/12/29 Javascript
jquery 关于event.target使用的几点说明介绍
2013/04/26 Javascript
JS画5角星方法介绍
2013/09/17 Javascript
jQuery实现的仿百度,仿谷歌搜索下拉框效果示例
2016/12/30 Javascript
jQuery中页面返回顶部的方法总结
2016/12/30 Javascript
原生JavaScript实现的简单省市县三级联动功能示例
2017/05/27 Javascript
前端构建工具之gulp的配置与搭建详解
2017/06/12 Javascript
node.js + socket.io 实现点对点随机匹配聊天
2017/06/30 Javascript
Vue项目中引入外部文件的方法(css、js、less)
2017/07/24 Javascript
webpack源码之loader机制详解
2018/04/06 Javascript
laypage.js分页插件使用方法详解
2019/07/27 Javascript
antd vue table跨行合并单元格,并且自定义内容实例
2020/10/28 Javascript
python中使用enumerate函数遍历元素实例
2014/06/16 Python
Python入门篇之面向对象
2014/10/20 Python
python遍历数组的方法小结
2015/04/30 Python
Python实现购物车功能的方法分析
2017/11/10 Python
python入门前的第一课 python怎样入门
2018/03/06 Python
Python3.6.0+opencv3.3.0人脸检测示例
2018/05/25 Python
python中pygame安装过程(超级详细)
2019/08/04 Python
Python实现自动访问网页的例子
2020/02/21 Python
keras .h5转移动端的.tflite文件实现方式
2020/05/25 Python
浅谈HTML5 &amp; CSS3的新交互特性
2016/07/19 HTML / CSS
HTML table 表格边框的实现思路
2019/10/12 HTML / CSS
HTML5输入框下拉菜单功能的示例代码
2020/09/08 HTML / CSS
陈欧的广告词
2014/03/18 职场文书
应用心理学专业求职信
2014/08/04 职场文书
交通事故起诉书
2015/05/19 职场文书
《圆的面积》教学反思
2016/02/19 职场文书