今天来实现一个可兼容的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. pl/sql实现打印九九乘法表

    学习PL/SQL循环的时候写的,记录一下. declare v_number1 ); -- 外层循环变量 v_number2 ); -- 内层循环变量 begin .. -- 开始外层循环 loop ...

  2. Git本地仓库push至GitHub远程仓库每次输入账户密码问题解决(亲测可行)

    在使用git push命令将本地仓库内容推送至GitHub远程仓库的每一次git都要让我们输入GitHub的用户名和密码.这着实让我们心烦.我们会有疑问,我明明设置了公钥呀!怎么还需要输入账户和密码? ...

  3. Android——MaterialDesign之一Toolbar

    Toolbar 由于ActionBar设计原因只能存在活动的顶部,从而不能实现MaterialDesign的效果,现在推荐使用Toolbar,继承Actionbar,但是比起它更加的灵活. 设置主题: ...

  4. Java内存泄漏分析

    https://www.javatang.com/archives/2017/11/08/11582145.html?tdsourcetag=s_pcqq_aiomsg

  5. Python OpenCV人脸识别案例

    ■环境 Python 3.6.0 Pycharm 2017.1.3 ■库.库的版本 OpenCV 3.4.1 (cp36) ■haarcascades下载 https://github.com/ope ...

  6. RN 实战 & React Native 实战

    RN 实战 & React Native 实战 https://abc.xgqfrms.xyz/react-native-docs/ 0.59 https://github.com/xgqfr ...

  7. vue 使用技巧总结 19.01

    组件中箭头函数的使用 不要使用箭头来定义任意生命周期钩子函数: 不要使用箭头来定义一个 methods 函数: 不要使用箭头来定义 computed 里的函数: 不要使用箭头定义 watch 里的函数 ...

  8. DotNetty 实现 Modbus TCP 系列 (二) ModbusFunction 类图及继承举例

    本文已收录至:开源 DotNetty 实现的 Modbus TCP/IP 协议 ModbusFunction 类图如下: 如前文所述,所有请求/相应的 PDU 均继承自 ModbusFunction, ...

  9. Running Web API using Docker and Kubernetes

    Context As companies are continuously seeking ways to become more Agile and embracing DevOps culture ...

  10. Nginx 防盗链 secure_link 模块

    L:76 需要通过 --with-http_secure_link_module 编译进Nginx secure_link 指令 Syntax: secure_link expression; Def ...