今天来研究下跟拖拽有关的问题,以备以后可以实现更多友好的交互形式。
1. 相关原生方法:
- ondragstart:拖拽开始
- ondragend:拖拽结束
- ondragenter:拖拽元素进入目标元素头上的时候
- ondrop:拖拽元素进入目标元素头上,同时鼠标松开的时候
- ondragover:拖拽元素在目标元素头上移动的时候
有点晕?按下面的例子分别都操作下就明白啦。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title><style type= text/css>.container {width: 400px;height: 400px;background: #ff6632;}</style>
</head>
<body><div id='drag1' draggable="true">拖拽我,come on!</div><div id='drag2'>拽不动我,come on!</div><div class='container' id='container'></div>
</body>
<script>document.getElementById('drag1').ondragstart = function(){console.log('开始拖拽')}document.getElementById('drag1').ondragend = function(){console.log('结束拖拽')}document.getElementById('container').ondrop = function(){console.log('已掉入规定范围')} document.getElementById('container').ondragenter = function(){console.log('拖拽元素进入目标元素头上的时候')} document.getElementById('container').ondragover = function(ev) {//防止ondrop不生效,ev.preventDefault()ev.preventDefault();console.log('拖拽元素在目标元素头上移动的时候')};</script>
</html>
复制代码
特别注意:
- 想对一个元素进行一系列的拖拽操作,要注明属性
draggable="true"
来激活它的可拖拽性。 - 在使用ondrop时,发现没有生效,在ondragover中需要阻止默认事件的触发。
到这里我们已经可以拖拽元素并且监听一系列的拖拽事件了,然而本文远远没有结束,我们接着往下看:
人家网页上的拖拽都是拖着元素可以随便动,我这写的什么玩意!元素根本都不能动,不好使啊!!!!
别着急,现在我们来让元素跟着拖拽动起来!!!
- 首先我们要搞清楚一些概念:
screenX,screenY
/offsetX,offsetY
/clientX,clientY
. 1. 1. --学习链接- getComputedStyle -- 学习链接
- 清楚了概念,我们看下具体实现。
html部分:
<style type='text/css'>#box {position: absolute;left: 100px;top: 100px;padding: 5px;background: #f0f3f9;width: 100px;height: 100px;}
</style>
...
<div id='box'></div>
复制代码
js部分:
window.onload = function () {var oBox = document.getElementById("box");startDrag(oBox, oBox);};var params = {left: 0,top: 0,currentX: 0,currentY: 0,flag: false};//获取相关CSS属性var getCss = function (o, key) {return o.currentStyle ? o.currentStyle[key] : document.defaultView.getComputedStyle(o, null)[key];};//拖拽的实现var startDrag = function (bar, target, callback) {if (getCss(target, "left") !== "auto") {params.left = getCss(target, "left");}if (getCss(target, "top") !== "auto") {params.top = getCss(target, "top");}//o是移动对象bar.onmousedown = function (event) {params.flag = true;var e = event;params.currentX = e.clientX;params.currentY = e.clientY;};document.onmouseup = function () {console.log('test')params.flag = false;if (getCss(target, "left") !== "auto") {params.left = getCss(target, "left");}if (getCss(target, "top") !== "auto") {params.top = getCss(target, "top");}};document.onmousemove = function (event) {var e = event ? event : window.event;if (params.flag) {var nowX = e.clientX, nowY = e.clientY;var disX = nowX - params.currentX, disY = nowY - params.currentY;target.style.left = parseInt(params.left) + disX + "px";target.style.top = parseInt(params.top) + disY + "px";}}};
复制代码
元素跟着动起来啦!
可以尝试把这里的 DEMO 和 drag 的方法合并使用,这里就不赘述啦。
上述为PC的拖动,我们把chrome的模拟器切到手机模式,oh myGod!!炫酷的效果全都失效了!!!!桑心~~~~
下面我们来看下移动端的拖拽操作:
在这之前先对touch事件有一个了解:学习链接
有一些不得不说的概念:
-
screenX: 触摸点相对于屏幕左边缘的 x 坐标。
-
screenY: 触摸点相对于屏幕上边缘的 y 坐标。
-
clientX: 触摸点相对于浏览器的 viewport左边缘的 x 坐标。不会包括左边的滚动距离。
-
clientY: 触摸点相对于浏览器的 viewport上边缘的 y 坐标。不会包括上边的滚动距离。
-
pageX: 触摸点相对于 document的左边缘的 x 坐标。 与 clientX不同的是,他包括左边滚动的距离,如果有的话。
-
pageY: 触摸点相对于 document的左边缘的 y 坐标。 与 clientY不同的是,他包括上边滚动的距离,如果有的话。
-
target: 总是表示 手指最开始放在触摸设备上的触发点所在位置的 element。即使已经移出了元素甚至移出了document, 他表示的element仍然不变
掌握了上述概念打开控制台,让我来观察元素的运动吧!!!
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title><style type="text/css">#content {width: 200px;height: 200px;background: #ff6632;position: absolute;left: 0;top: 0;}</style>
</head><body><div id="content">test</div>
</body>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>(function (window) { //传入window,提高变量的查找效率function myQuery(selector) { //这个函数就是对外提供的接口。//调用这个函数的原型对象上的_init方法,并返回return myQuery.prototype._init(selector);}myQuery.prototype = {/*初始化方法,获取当前query对象的方法*/_init: function (selector) {if (typeof selector == "string") {//把查找到的元素存入到这个原型对象上。this.ele = window.document.querySelector(selector);//返回值其实就是原型对象。return this;}},/*单击事件:* 为了规避click的300ms的延迟,自定义一个单击事件* 触发时间:* 当抬起手指的时候触发* 需要判断手指落下和手指抬起的事件间隔,如果小于500ms表示单击时间。** 如果是大于等于500ms,算是长按时间* */tap: function (handler) {this.ele.addEventListener("touchstart", touchFn);this.ele.addEventListener("touchend", touchFn);var startTime,endTime;function touchFn(e) {e.preventDefault()switch (e.type) {case "touchstart":startTime = new Date().getTime();break;case "touchend":endTime = new Date().getTime();if (endTime - startTime < 500) {handler.call(this, e);}break;}}},/*** 长按* @param handler*/longTag: function (handler) {this.ele.addEventListener("touchstart", touchFn);this.ele.addEventListener("touchmove", touchFn);this.ele.addEventListener("touchend", touchFn);var timerId;function touchFn(e) {switch (e.type) {case "touchstart": //500ms之后执行timerId = setTimeout(function () {handler.call(this, e);}, 500)break;case "touchmove"://如果中间有移动也清除定时器clearTimeout(timerId)break;case "touchend"://如果在500ms之内抬起了手指,则需要定时器clearTimeout(timerId);break;}}},/*** 左侧滑动。记录手指按下的左边,在离开的时候计算 deltaX是否满足左滑的条件**/slide: function (handler) {this.ele.addEventListener("touchstart", touchFn);this.ele.addEventListener("touchend", touchFn);var startX, startY, endX, endY;function touchFn(e) {e.preventDefault();var firstTouch = e.changedTouches[0];switch (e.type) {case "touchstart":startX = firstTouch.pageX;startY = firstTouch.pageY;break;case "touchend":endX = firstTouch.pageX;endY = firstTouch.pageY;//x方向移动大于y方向的移动,并且x方向的移动大于25个像素,表示在向左侧滑动if (Math.abs(endX - startX) >= Math.abs(endY - startY) && startX - endX >= 25) {handler.call(this, e, 'left');}else if(Math.abs(endX - startX) >= Math.abs(endY - startY) && startX - endX < -25){handler.call(this, e, 'right');}else if(Math.abs(endX - startX) < Math.abs(endY - startY) && startY - endY >= 25){handler.call(this, e, 'up');}else if(Math.abs(endX - startX) < Math.abs(endY - startY) && startY - endY < -25){handler.call(this, e, 'down');}break;}}},/*** 右侧滑动。**/slideRight: function (e) {}}window.$$ = window.myQuery = myQuery;})(window);$$("div").tap(function (e) {console.log("单击事件")})$$("div").slide(function (e, type) {let content = ''console.log(this);type === 'left' && (content = "左侧滑动了.....");type === 'right' && (content = "右侧滑动了...."); type === 'up' && (content = "向上滑动了...."); type === 'down' && (content = "向下滑动了....");this.innerHTML = content;})$$("div").longTag(function () {console.log("长按事件");})var _x_start, _y_start, _x_move, _y_move, _x_end, _y_end, left_start, top_start;document.getElementById("content").addEventListener("touchstart", function (e) {_x_start = e.touches[0].pageX;_y_start = e.touches[0].pageY;left_start = $("#content").css("left");top_start = $("#content").css("top");})document.getElementById("content").addEventListener("touchmove", function (e) {_x_move = e.touches[0].pageX;_y_move = e.touches[0].pageY;$("#content").css("left", parseFloat(_x_move) - parseFloat(_x_start) + parseFloat(left_start) + "px");$("#content").css("top", parseFloat(_y_move) - parseFloat(_y_start) + parseFloat(top_start) + "px");})document.getElementById("content").addEventListener("touchend", function (e) {// var _x_end=e.changedTouches[0].pageX;// var _y_end=e.changedTouches[0].pageY;// console.log("end",_x_end)})//阻止浏览器下拉事件$('body').on('touchmove', function (event) { event.preventDefault(); });
</script></html>
复制代码
是不是觉得可以很自由的操控一个元素了?哈哈哈。。。
接下来我们在看一个进度条的例子:
这里有一点对range
的扩展,有兴趣的可以了解一下,不看也不影响理解。--学习链接
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title><style type="text/css">.scroll {top: 100px;left: 100px;position: relative;width: 500px;height: 5px;background: rgb(180, 180, 180);}.bar {position: absolute;top: -3px;height: 10px;width: 8px;background: rgb(255, 0, 0);}.mask {position: absolute;height: 5px;background: rgb(255, 0, 0);}</style>
</head>
<body><div class="scroll"><div class="bar"></div><div class="mask"></div></div><p></p>
</body><script>// debuggervar bar = document.getElementsByClassName('bar')[0];var scroll = document.getElementsByClassName('scroll')[0];var bar = document.getElementsByClassName('bar')[0];var mask = document.getElementsByClassName('mask')[0];bar.onmousedown = function(e){var leftVal = e.clientX - this.offsetLeft;var that = this;document.onmousemove = function(e){barLeft = e.clientX - leftVal;if(barLeft < 0){barLeft = 0}else if(barLeft > scroll.offsetWidth - bar.offsetWidth){barLeft = scroll.offsetWidth - bar.offsetWidth;}bar.style.left = barLeft + 'px';mask.style.width = barLeft + 'px';document.getElementsByTagName('p')[0].innerHTML = '已经完成了' + Math.floor((barLeft / (scroll.offsetWidth - bar.offsetWidth))*100) + '%' //防止拖动过快时鼠标弹起后mousemove还在生效window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();}}document.onmouseup = function () {document.onmousemove = null; //弹起鼠标不做任何操作}
</script>
</html>
复制代码
是不是感觉还挺实用的,哈哈哈!
好啦,今天先扯到这里。
end。。。。。