今天来实现一个可兼容的js原生拖拽,在这里面我将会讲到:

1.封装兼容性的事件系统。

2.封装得到鼠标当前位置的系统。

3.完成拖拽的实现。

首先,我们要讲到鼠标位置的获取,讲到这个,就离不开js的window.event事件了。先展开一个例子:

 <div id="drag"></div>
 *{margin:;padding:}
#drag{
position: absolute;
top: 100px;
left: 200px;
width: 60px;height: 60px;
background-color: red;
}

当我点击红色div的中间偏上的地方,打印他的event对象,看到里面给了好多属性,我们来一一解释一下。先盗一个表:

名称 解释
clientX 事件属性返回当事件被触发时鼠标指针向对于浏览器页面(或客户区)的水平坐标。
clientY 事件属性返回当事件被触发时鼠标指针向对于浏览器页面(客户区)的垂直坐标。
screenX 事件属性可返回事件发生时鼠标指针相对于屏幕的水平坐标。
screenY 事件属性可返回事件发生时鼠标指针相对于屏幕的垂直坐标。
offsetX 事件发生的地点在事件源元素的坐标系统中的 x 坐标(ie)。
offsetY 事件发生的地点在事件源元素的坐标系统中的 y 坐标(ie)。
x 事件发生的位置的 x 坐标, 它相对于用CSS动态定位的最内层包容元素(ie,~pageX)。
y 事件发生的位置的 y 坐标, 它相对于用CSS动态定位的最内层包容元素(ie,~pageY)。
pageX 鼠标指针的位置,相对于文档的左边缘(firefox,~x)。
pageY 鼠标指针的位置,相对于文档的上边缘(firefox,~y)。
layerX 鼠标相比较于当前坐标系的位置(firefox,~offsetX)。
layerY 鼠标相比较于当前坐标系的位置(firefox,~offsetY)。

然后把刚刚的图截完:

我这个div的宽60,高60,left:200,top:100;

clientX/Y:可以看到它的clientX是229,根据表里的描述,它是鼠标指针到浏览器页面,不包含浏览器的工具栏什么的。因为我点的大约是div的中部最上面,所以它的值就等于top值:100px。X的229就是200的left加上了一半的宽30---就是230左右。(由于我随便点的,不准确,但是基本接近)。

screenX/Y:相对于屏幕的,可以看到X没怎么变,Y变成了163。就是因为它有61px的工具栏和导航栏的高度。so,你把浏览器缩小,它还是相对于屏幕,而不是浏览器,你会发现它就和上一个差太多了。

offsetX/Y:这个就比较有用了,鼠标相对于这个元素的位置,offset嘛,就是相对了。可以看到x是29,y是2,因为我大约点的中间。

x/y: 相对于它父元素的位置,相当于firefox中的pageX、pageY坐标。当父元素是document的时候就跟clientX/Y一样。因为它的父元素就是document。。。所以跟上面那几个一样。说是ie特有,不过我chrome上面也有这个属性。但是我chrome的x,y的属性就算你有父元素还是等于clientX/Y,高版本ie也是如此。大家就把它记作clientX/Y就好。

layerX/Y:其实就是offsetX/Y,不过offsetX/Y是ie的属性,layerX/Y是firefox支持的。chrome我这个版本都支持了。

pageX/Y:鼠标指针的位置,相对于文档的左边缘和上边缘,是firefox中支持的,相似于ie中的x和y。和client区别就是如果有滚动条,他是大于client的

总结一下:clientX/Y== X/Y==无滚动条下pageX/Y    offsetX/Y==layerX/Y  screenX/Y相对于屏幕,就它自己。

那回到我们取鼠标坐标,怎么办呢,看能用到哪个属性:clientX/Y这就是鼠标真正的坐标,相对于本页面的坐标。然后offsetX/Y是相对于div的偏移。那么这个div的位置就是pageX/Y-offsetX/Y;大家打印一下,就能知道x总是返回100,y返回200;

那我们开始写取坐标的位置的兼容js:

function getPosition(e){
e=e||window.event;
var target=e.target?e.target:e.srcElement; //兼容ie的srcElement var pos_rel={};
var pos_offset={};
pos_rel={
x:e.pageX?e.pageX:e.clientX+(document.body.scrollLeft||document.documentElement.scrollLeft),//clientX加上滚动条滚动的位置
y:e.pageY?e.pageY:e.clientY+(document.body.scrollTop||document.documentElement.scrollTop)
}
pos_offset={
x:e.offsetX?e.offsetX:e.layerX,
x:e.offsetY?e.offsetY:e.layerY
}
return {
rel:pos_rel,
offset:pos_offset
}
}

取到这个位置就好做拖拽了。就是让鼠标点击的时候记录相对于div的x,y,鼠标移动设置div的left和top,记得减去刚刚记录的offsetX/Y。鼠标松开就设置不能移动。

好,在这之前先说一下封装事件系统

事件系统就是为了ie不支持addEventListener才做的封装兼容

别的浏览器可以addEventListener和removeEventListener,而ie的是attachEvent和detachEvent。ie的这个和addEventListener用法是相似的,需要注意的一点就是要把处理事件保存用以解除监听。

我上一下我写的事件封装:

var addEvent=function(el,event,cb){
if (el.addEventListener) {
el.addEventListener(event,cb);
}else if(el.attachEvent){
el.attachEvent(event,cb);
}
return cb; //注意这里返回处理函数
}
var cancelEvent=function(el,event,cb){
if (el.removeEventListener) {
el.removeEventListener(event,cb);
}else if(el.detachEvent){
el.detachEvent('on'+event,cb)
}
}

使用就是

var handle=addEvent(document,"click",function(e){
console.log("be clicked")
})

解除事件监听:

cancelEvent(document,"click",handle)

这里我没有写第三个参数,默认冒泡添加解除事件,有需要也可以多加参数。

好,那么开始写拖拽吧:

首先点击这个div记录当前offsetX,Y

var isDrag=false;var ofx,ofy;
var mousedownH=addEvent(drag,"mousedown",function(e){
isDrag=true;
ofx=getPosition().offset.x;
ofy=getPosition().offset.y;
})

然后设置div位置:

var mousemoveH=addEvent(document,"mousemove",function(e){  //注意这里的mousemove和mouseup都是在document上的事件,这是为了避免你鼠标移动太快,移出了这个div,就没有move事件触发了。
if(isDrag) {
var relX=getPosition().rel.x-ofx;
var relY=getPosition().rel.y-ofx;
drag.style.left=relX+"px";
drag.style.top=relY+"px";
};
})

最后鼠标抬起取消它的可移动:

var mouseupH=addEvent(document,"mouseup",function(e){
isDrag=false;
})

搞定。

最后把全部代码分享,大家复制就可以用了

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js拖拽</title>
<style type="text/css">
*{margin: 0;padding: 0}
#drag{
position: absolute;
top: 100px;
left:200px;
width: 60px;height: 60px;
background-color: red;
}
</style>
</head>
<body>
<div id="drag"></div>
</body>
<script type="text/javascript">
var drag=document.getElementById('drag');
var click1=document.getElementById('click');
var can=document.getElementById('can');
var addEvent=function(el,event,cb){
if (el.addEventListener) {
el.addEventListener(event,cb);
}else if(el.attachEvent){
el.attachEvent(event,cb);
}
return cb;
}
var cancelEvent=function(el,event,cb){
if (el.removeEventListener) {
el.removeEventListener(event,cb);
}else if(el.detachEvent){
el.detachEvent('on'+event,cb)
}
}
function getPosition(e){
e=e||window.event;
var target=e.target?e.target:e.srcElement; var pos_rel={};
var pos_offset={};
pos_rel={
x:e.pageX?e.pageX:e.clientX+(document.body.scrollLeft||document.documentElement.scrollLeft),
y:e.pageY?e.pageY:e.clientY+(document.body.scrollTop||document.documentElement.scrollTop)
}
pos_offset={
x:e.offsetX?e.offsetX:e.layerX,
x:e.offsetY?e.offsetY:e.layerY
}
return {
rel:pos_rel,
offset:pos_offset
}
}
var isDrag=false;var ofx,ofy;
var mousedownH=addEvent(drag,"mousedown",function(e){
isDrag=true;
ofx=getPosition().offset.x;
ofy=getPosition().offset.y;
})
var mousemoveH=addEvent(document,"mousemove",function(e){
if(isDrag) {
var relX=getPosition().rel.x-ofx;
var relY=getPosition().rel.y-ofx;
drag.style.left=relX+"px";
drag.style.top=relY+"px";
};
})
var mouseupH=addEvent(document,"mouseup",function(e){
isDrag=false;
})
</script>
</html>

js原生事件系统与坐标系统的更多相关文章

  1. js原生代码实现轮播图案例

    一.轮播图是现在网站网页上最常见的效果之一,对于轮播图的功能,要求不同,效果也不同! 我们见过很多通过不同的方式,实现这一效果,但是有很多比较麻烦,而且不容易理解,兼容性也不好. 在这里分享一下,用j ...

  2. JS原生效果瀑布流布局的实现(一)

    JS原生效果 实现: HTML页面布局: <!DOCTYPE html> <html> <head> <meta charset="utf-8&qu ...

  3. 工作当中实际运用(3)——js原生实现鼠标点击弹出div层 在点击隐藏

    function onmou(){ var divs=document.getElementById('kefuDV');//获取到你要操作的div if (divs.style.display==& ...

  4. 仿jQuery的siblings效果的js原生代码

    仿jQuery的siblings效果的js原生代码 <previousSibling> 属性返回选定节点的上一个同级节点(在相同树层级中的前一个节点). <nextSibling&g ...

  5. js原生的url操作函数,及使用方法。(附:下边还有jquery对url里的中文解码函数)

    js原生的url操作函数,完善的. /*****************************/ /* 动态修改url */ /*****************************/ var ...

  6. 图片轮播(左右切换)--JS原生和jQuery实现

    图片轮播(左右切换)--js原生和jquery实现 左右切换的做法基本步骤跟 上一篇文章  淡入淡出 类似,只不过修改了一些特定的部分 (1)首先是页面的结构部分 对于我这种左右切换式 1.首先是个外 ...

  7. 图片轮播(淡入淡出)--JS原生和jQuery实现

    图片轮播(淡入淡出)--js原生和jquery实现 图片轮播有很多种方式,这里采用其中的 淡入淡出形式 js原生和jQuery都可以实现,jquery因为封装了很多用法,所以用起来就简单许多,转换成j ...

  8. 手把手教你js原生瀑布流效果实现

    手把手教你js原生瀑布流效果实现 什么是瀑布流效果 首先,让我们先看一段动画: 在动画中,我们不难发现,这个动画有以下特点: 1.所有的图片的宽度都是一样的 2.所有的图片的高度是不一样的 3.图片一 ...

  9. js原生 + jQuery实现页面滚动字幕

    js原生/jQuery实现页面滚动字幕效果 17:45:49 在新闻列表或者文章列表信息等页面中很容易要求实现字幕滚动的效果,以下为简单的实现页面中滚动字幕的效果 1.jQuery实现页面滚动字幕效果 ...

随机推荐

  1. [转帖]FORFILES 的简单介绍。

    FORFILES https://blog.csdn.net/sandy9919/article/details/82932460 命令格式: forfiles.exe /p "D:\备份& ...

  2. STL 序列容器

    转自时习之 STL中大家最耳熟能详的可能就是容器,容器大致可以分为两类,序列型容器(SequenceContainer)和关联型容器(AssociativeContainer)这里介绍STL中的各种序 ...

  3. mysql修改默认端口号后从windows命令行登录

    mysql -u root -p -P 大写的P代表端口号,小写的p代表密码

  4. Ionic常用命令

    安装ionic npm install -g ionic 更新www/lib/ionic 目录的文件,如有项目中有bower,此命令会运行bower update ionic, 否则则会从CDN上下载 ...

  5. j收集ava面试题

    史上最全Java面试题(带全部答案) https://blog.csdn.net/linzhiqiang0316/article/details/80473906

  6. Struts2——namespace、action、以及path问题

    简单的介绍下Struts2中的几个简单的问题(namespace.action.以及path问题) namespace(命名空间) Namespace决定了action的访问路径,默认为“”,意味着可 ...

  7. Linux基础学习(11)--Shell编程

    第十一章——Shell编程 一.基础正则表达式 1.正则表达式与通配符(*,?,[ ]): 2.基础正则表达式: 二.字符截取命令 1.cut字段提取命令: 空格分割时,不知道空格有多少个,无法分割行 ...

  8. Linux基础学习(10)--Shell基础

    第十章——Shell基础 一.Shell概述 1.Shell是什么: (1)Shell是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用Shell来 ...

  9. linux audit审计(5)--audit规则配置

    audit可以配置规则,这个规则主要是给内核模块下发的,内核audit模块会按照这个规则获取审计信息,发送给auditd来记录日志. 规则类型可分为: 1.控制规则:控制audit系统的规则: 2.文 ...

  10. C# 将当前应用程序写入到注册表开机启动项中

    在使用C#进行应用程序的开发过程中,经常有一个需求就是让应用程序开机后自动启动,这个是一个很常见的需求,最常规的做法(这里以Win7操作系统为例),打开:开始=>所有程序=>启动文件夹(路 ...