javascript 事件处理、鼠标拖动效果实现方法详解


Posted in Javascript onMay 11, 2012

先看看要拖动的层(模拟窗口)的效果图吧。

javascript 事件处理、鼠标拖动效果实现方法详解
要实现的拖动效果:鼠标左键在窗口上方的标题栏上按下,同时移动鼠标,窗口跟着移动。
窗口:

<div id="win"> 
<div id="win_header"></div> 
</div>

一点准备工作:
要让窗口能自由移动,那么窗口的定位(position)应该采用绝对定位(absolute);
给窗口添加标题栏,这里使用一个放在窗口顶部的层实现,同时将标题栏的鼠标光标设置为拖动(move)形状(在chrome中拖动的时候,光标会变成文字光标,松开鼠标键后恢复)。
#win { 
position:absolute; 
width:480px; 
height:320px; 
background-color:#d4d4d4; 
border: 1px solid #4d4d4d; 
} 
#win_header { 
width:480px; 
height:48px; 
background-color:#4d4d4d; 
cursor:move; 
}

定义一个工具函数,用来获取指定ID属性的元素:
function $id(id) { 
return document.getElementById(id); 
}

定义一个浏览器核心标识isIE:
var isIE = (window.navigator.userAgent.indexOf("IE") == -1) ? false : true;
获取到窗口元素及其标题栏:
var win = $id("win"); 
var header = $id("win_header");

为了方便记录鼠标和窗口的位置信息,创建一个位置:
var pos =function(x, y) { 
this.x = x; 
this.y = y; 
};

给窗口设置一个初始位置(css的left值和top值)。
这里不知道是为什么,如果不使用js设置这两个属性,就取不到值,在CSS中指定了也不行。
var originalpos = new pos(20, 20);

在拖动窗口的过程中,需要记录的值有:
鼠标按下时鼠标光标的位置
var oldmouse =new pos(0, 0);

鼠标按下时窗口的位置
var oldpos = new pos(0, 0);
鼠标移动时窗口的新的位置
var newpos = new pos(0, 0);
设置窗口的初始位置
win.style.left = originalpos.x + "px"; 
win.style.top = originalpos.y + "px";

又是因为浏览器的差异(IE和非IE),元素绑定事件处理函数的方法不同(IE使用attachEvent,非IE使用addEventListener),为了简化事件绑定的操作,定义一个事件绑定函数:
function bind(ev, func) { 
if(isIE) { 
header.attachEvent("on" + ev, func); 
} else { 

header.addEventListener(ev, func, false); 
} 
}

在做好这些工作后,就可以开始处理鼠标事件了。
在这个程序中,只希望鼠标左键拖动窗口,其它键都不能,所以需要判断是否是鼠标左键按下。而这个判断会在几个函数中都使用到,所以提取出来到一个函数中,通过传入的参数(鼠标键值,即按下了哪个键)判断。在这里,需要注意浏览器间的差异:IE中鼠标左键的值是1,而非IE中值是0.
function isLeftButton(btn) { 
if(isIE) { 
if(btn == 1) 
return true; 
else 
return false; 
} else { 
if(btn == 0) 
return true; 
else 
return false; 
} 
}

拖动动作是在按下鼠标左键后移动来完成的。把这个动作分享开来,即是鼠标先触发了按下动作(mousedown),然后触发了移动动作(mousemove)。为了判断是否是真的在拖动还是只是鼠标从窗口上经过,设置一个变量来记录鼠标按下的状态:
var mousedown = false;
由于CSS中存在的兼容性问题,这里使用js来控制鼠标悬停在窗口标题栏上面的时候的颜色变化。
悬浮
function over(e){ 
header.style.backgroundColor = "#5d5d5d"; 
}

离开
function out(e) { 
header.style.backgroundColor = "#4d4d4d"; 
// 有时候鼠标会在未松开的情况下离开窗口, 
// 此时通过触发鼠标的松开事件来使窗口脱离鼠标的控制 
up(e); 
}

按下
在按下事件中,需要先判断是否按下的是鼠标的左键;
若是才记录鼠标和窗口此时的位置,否则不记录。
function down(e) { 
e = e || event; 
if(!isLeftButton(e.button)) 
return; 
mousedown = true; 
oldmouse.x = e.clientX; 
oldmouse.y = e.clientY; 
oldpos.x = parseInt(win.style.left.replace("px", "")); 
oldpos.y = parseInt(win.style.top.replace("px", "")); 
}

松开
function up(e) { 
if(!isLeftButton(e.button)) 
return; 
mousedown = false; 
}

移动
这里就涉及到鼠标的两个事件:
按下和移动。当且仅当鼠标左键按下时,移动动作才有效。
窗口的新位置,是由鼠标在拖动状态下的移动距离(X和Y的距离)决定的。即:
新的鼠标位置送去按下左键时记录下的位置,得到一个距离,然后将窗口的位置加上鼠标移动的距离得到窗口的新位置。
function move(e) { 
if(!isLeftButton(e.button)) 
return; 
if(mousedown) { 
e =e || event; 
newpos.x = e.clientX - oldmouse.x; 
newpos.y = e.clientY - oldmouse.y 
win.style.left = (oldpos.x + newpos.x) + "px"; 
win.style.top = (oldpos.y + newpos.y) + "px"; 
} 
}

事件处理都写好了,最后来给元素绑定上吧,阿门!
bind("mouseover", over); 
bind("mouseenter", over); 
bind("mouseout", out); 
bind("mouseleave", out); 
bind("blur", out); 
bind("mousedown", down); 
bind("mouseup", up); 
bind("mousemove", move);

不过在FF中的拖动有问题,只能第一次正常拖动,后面就有点乱了!
Javascript 相关文章推荐
jQuery数组处理代码详解(含实例演示)
Feb 03 Javascript
将JavaScript的jQuery库中表单转化为JSON对象的方法
Nov 17 Javascript
详解JavaScript的AngularJS框架中的作用域与数据绑定
Mar 04 Javascript
BootStrap中的table实现数据填充与分页应用小结
May 26 Javascript
关于JavaScript中事件绑定的方法总结
Oct 26 Javascript
搭建Bootstrap离线文档的方法
Dec 02 Javascript
JS实现焦点图轮播效果的方法详解
Dec 19 Javascript
javascript将url解析为json格式的两种方法
Aug 18 Javascript
如何用webpack4.0撸单页/多页脚手架 (jquery, react, vue, typescript)
Jun 18 jQuery
浅谈React中组件逻辑复用的那些事儿
May 21 Javascript
在HTML中使用JavaScript的两种方法
Dec 24 Javascript
vue实现列表拖拽排序的示例代码
Apr 08 Vue.js
通过百度地图获取公交线路的站点坐标的js代码
May 11 #Javascript
疯狂Jquery第一天(Jquery学习笔记)
May 11 #Javascript
jQuery 过滤not()与filter()实例代码
May 10 #Javascript
jQuery 在光标定位的地方插入文字的插件
May 10 #Javascript
javascript 在firebug调试时用console.log的方法
May 10 #Javascript
jQueryUI写一个调整分类的拖放效果实现代码
May 10 #Javascript
基于jQuery捕获超链接事件进行局部刷新代码
May 10 #Javascript
You might like
php foreach循环中使用引用的问题
2013/11/06 PHP
php实现专业获取网站SEO信息类实例
2015/04/02 PHP
PHP查找与搜索数组元素方法总结
2015/06/12 PHP
php实现基于pdo的事务处理方法示例
2017/07/21 PHP
PHP实现求两个字符串最长公共子串的方法示例
2017/11/17 PHP
this[] 指的是什么内容 讨论
2007/03/24 Javascript
JQuery从头学起第三讲
2010/07/06 Javascript
js替代copy(示例代码)
2013/11/27 Javascript
DOM节点的替换或修改函数replaceChild()用法实例
2015/01/12 Javascript
详解JavaScript函数对象
2015/11/15 Javascript
AngularJs  unit-testing(单元测试)详解
2016/09/02 Javascript
使用jQuery,Angular实现登录界面验证码详解
2017/04/27 jQuery
jQuery扇形定时器插件pietimer使用方法详解
2017/07/18 jQuery
通过nodejs 服务器读取HTML文件渲染到页面的方法
2018/05/17 NodeJs
vue中promise的使用及异步请求数据的方法
2018/11/08 Javascript
微信小程序 腾讯地图显示偏差问题解决
2019/07/27 Javascript
关于Layui Table隐藏列问题
2019/09/16 Javascript
[04:16]DOTA2英雄梦之声_第09期_斧王
2014/06/21 DOTA
python写入xml文件的方法
2015/05/08 Python
Python进阶篇之字典操作总结
2016/11/16 Python
Python如何import文件夹下的文件(实现方法)
2017/01/24 Python
Python中import机制详解
2017/11/14 Python
Python面向对象之类和对象属性的增删改查操作示例
2018/12/14 Python
python去重,一个由dict组成的list的去重示例
2019/01/21 Python
Python3.6实现带有简单界面的有道翻译小程序
2019/04/16 Python
Django实现从数据库中获取到的数据转换为dict
2020/03/27 Python
Python 合并拼接字符串的方法
2020/07/28 Python
HTML5新增元素如何兼容旧浏览器有哪些方法
2014/05/09 HTML / CSS
NICKIS.com荷兰:设计师儿童时装
2020/01/08 全球购物
简述使用ftp进行文件传输时的两种登录方式?它们的区别是什么?常用的ftp文件传输命令是什么?
2016/11/20 面试题
住房公积金接收函
2014/01/09 职场文书
2015年环卫工作总结
2015/04/28 职场文书
2016年度师德标兵先进事迹材料
2016/02/26 职场文书
如何利用JavaScript实现二叉搜索树
2021/04/02 Javascript
详解CSS不受控制的position fixed
2021/05/25 HTML / CSS
golang实现浏览器导出excel文件功能
2022/03/25 Golang