原生Javascript拖放程序

自己造轮子写个原生拖放,要做到简单调用,考虑拖放对象所在的环境,还要兼容老IE,还是挺锻炼人的。
主要碰到几个问题:

  1. 关于冒泡和阻止默认事件,以前的理解都很粗略,自己写的时候才知要细分。
    一是要阻止事件传递,即事件冒泡,老IE里是ev.cancelBubble=true,其他浏览器是ev.stopPropagation(),要在onmousedown的时候就定义好;
    然后是阻止默认事件,主要是为了防止图片无法拖动的问题,要在onmousemove的时候,老IE里是ev.returnValue=false; 其他浏览器ev.preventDefault()
  2. 拖动过程中鼠标移出物件,就要把事件方法在document上复制一遍:document.onmousemove=_self.onmousemove; 并且考虑到拖放结束的时候鼠标可能是在任意位置,那就干脆把onmouseup方法写在document上
  3. 单纯的拖放物件其实没什么用,实际应用的时候肯定会给拖放增加范围,比如自制的滚动条,幻灯效果等。所以给拖放对象的父级元素作边界。于是又重温了各种位置取值的兼容问题,getBoundingClientRect()是一个很有用的函数,不过在老IE里面取不到宽高,所以要自己计算一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
function dragObj(obj, objEdge){ //obj为拖放对象;objEdge为布尔值,为true则obj的父对象作为拖放的边界
 
	function getScrollOffsets(_w) {//获取页面的滚动位置函数
		_w = _w || window;
		//for all and IE9+
		if (_w.pageXOffset != null) return {
			x: _w.pageXOffset,
			y: _w.pageYOffset
		};
		//for IE678
		var _d = _w.document;
		if (document.compatMode == "CSS1Compat") return { //for IE678
			x: _d.documentElement.scrollLeft,
			y: _d.documentElement.scrollTop
		};
		//for other mode
		return {
			x: _d.body.scrollLeft,
			y: _d.body.scrpllTop
		};
	}
 
	var _self=obj;
	this._self=_self;
 
	if(objEdge) {//初始化边界的属性,如果是图片的话必须页面加载初始化,否则探测不到图片的宽高。也可以放在点击事件处理程序中,这样不需要等页面加载完毕
		var _edge=_self.parentNode;
		this._edge=_edge;
		//初始化目标样式
		if(!_self.style.top) {
			_self.style.top=( _self.getBoundingClientRect().top-_edge.getBoundingClientRect().top )+"px";
 
		}
		if(!_self.style.left) {
			_self.style.left=( _self.getBoundingClientRect().left-_edge.getBoundingClientRect().left )+"px";
		}
		if(!_self.style.position) _self.style.position="absolute"; 
		if(!_self.style.display || _self.style.display=="inline") _self.style.display="block";
 
		//初始化边界样式和移动固定区域
 
		if(!_edge.style.display || _edge.style.display=="inline") _edge.style.display="block"; 
		var edgeSizeWidth=_edge.getBoundingClientRect().right-_edge.getBoundingClientRect().left;//边界尺寸
		var edgeSizeHeight=_edge.getBoundingClientRect().bottom-_edge.getBoundingClientRect().top;
 
		var dragObjSizeWidth=_self.getBoundingClientRect().right-_self.getBoundingClientRect().left;//拖动对象尺寸
		var dragObjSizeHeight=_self.getBoundingClientRect().bottom-_self.getBoundingClientRect().top;
 
		_edge.w=edgeSizeWidth-dragObjSizeWidth;
		_edge.h=edgeSizeHeight-dragObjSizeHeight;
 
	} else {//无边界元素,在页面自由移动
		if(!_self.style.top) {_self.style.top = _self.getBoundingClientRect().top + getScrollOffsets().y + "px"}
		if(!_self.style.left) {_self.style.left = _self.getBoundingClientRect().left + getScrollOffsets().x + "px"}
		if(!_self.style.position || _self.style.position!="absolute" ) _self.style.position="absolute"; 
		if(!_self.style.display || _self.style.display=="inline") _self.style.display="block";
		var _edge=document.body;
	}
 
 
	_self.mousePosition= function(ev){ 
		ev = ev || window.event;
		var target = ev.target || ev.srcElement; // 获得事件源
		if(ev.pageX || ev.pageY){ 
			return {x:ev.pageX, y:ev.pageY}; 
		} 
		return { 
			x:ev.clientX + document.body.scrollLeft - document.body.clientLeft, 
			y:ev.clientY + document.body.scrollTop - document.body.clientTop 
		}; 
	}
 
	_self.onmousedown=function(ev){
 
		ev = ev || window.event;
		var startY=_self.mousePosition(ev).y-parseInt(_self.style.top);
		var startX=_self.mousePosition(ev).x-parseInt(_self.style.left);
 
		if (ev && ev.preventDefault) {//阻止事件传播冒泡
			ev.stopPropagation();
		}else if (document.all){
			ev.cancelBubble=true;
		}
 
		_self.onmousemove=function(ev){
			ev = ev || window.event;
 
			var poX=_self.mousePosition(ev).x-startX;
			var poY=_self.mousePosition(ev).y-startY;
			if(objEdge){
				if(poX<0) poX=0;
				if(poX>_edge.w) { poX=_edge.w; }
				if(poY<0) poY=0;
				if(poY>_edge.h) { poY=_edge.h; }
			}
			_self.style.left=poX+"px";
			_self.style.top=poY+"px";
 
			if (ev && ev.preventDefault) {//阻止默认事件,比如图片拖动问题
				ev.preventDefault();
			}else if (document.all){
				ev.returnValue = false;
			}
 
		}
 
		_self.onmouseout=function(ev){//如果鼠标移出了物件,用文档接受鼠标事件
			document.onmousemove = _self.onmousemove;
		}
 
		document.onmouseup=function(){//放开鼠标,释放所有相关事件
			_self.onmousemove=null;
			document.onmousemove=null;
			_self.onmouseout=null;
		}
 
	}
 
}

兼容IE6-11以及其他主流浏览器,调用方法:

1
2
var d1=new dragObj(document.getElementById("objID"), true);//父级元素自动作为边界
var d2=new dragObj(document.getElementById("objID"), false);//无边界,在窗口内部自由拖动,false也可以省略

本站所有文章均为原创,欢迎转载,请注明文章出处:https://blog.brain1981.com/501.html。百度不可信,搜索请谨慎。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以获取本文的最新版本。

关注我们的微信公众号-JennyStudio 本站记录了近几年的工作中遇到的一些技术问题和解决过程,“作品集”还收录了本人的大部分作品展示。除了本博客外,我们的工作室网站 – JennyStudio,内有更多作品回顾和展示。
您也可以扫描左边的二维码,关注我们的微信公众号,在微信上查看我们的案例。

发表评论

电子邮件地址不会被公开。 必填项已用*标注