移动前端页面开发:实现页面元素拖动

很少写博客,今天分享一个前几天研究的用JS实现页面元素的拖动。看官轻拍,大牛请多指教。

效果如图:

移动前端页面开发:实现页面元素拖动

  1. 页面触摸的三个事件函数:

    1)三个在规范中列出并获得跨移动设备广泛实现的基本触摸函数:touchstart, touchmove, touchend。

    (1)touchstart: 手指触摸一个DOM元素;

    (2)touchmove: 手指在触摸DOM元素之后在屏幕上移动;

    (3)touchend: 手指放开触摸的元素。

    2)每个触摸事件都包括了三个触摸列表:

    (1)touchs: 当前位于屏幕上的所有手指的一个列表;

    (2)targetTouchs: 位于当前DOM元素上的手指的列表;

    (3)chargedTouchs: 涉及当前事件的手指的列表。如:在touchend事件中,就是松开的手指。


  2. 页面元素定位

    当拖动元素时,使被拖动元素定位为:绝对定位,并根据触摸手指的offsetTop值来定位被拖动元素的top值。

    然后,在被拖动到的位置添加一个空的元素(如li),如果松开触摸,则将被拖动元素添加到该li位置并删除空白li元素。

  3. clientHeight,scrollTop,offsetTop

    要计算手指的拖动位置,需要获取到DIV的scrollTop和offsetTop值等。

    下面截取从网上获取的详细解释。

    移动前端页面开发:实现页面元素拖动


    假设 obj 为某个 HTML 控件。

    obj.offsetTop 指 obj 相对于版面或由 offsetParent 属性指定的父坐标的计算上侧位置,整型,单位像素。

    obj.offsetLeft 指 obj 相对于版面或由 offsetParent 属性指定的父坐标的计算左侧位置,整型,单位像素。

    obj.offsetWidth 指 obj 控件自身的绝对宽度,不包括因 overflow 而未显示的部分,也就是其实际占据的宽度,整型,单位像素。

    obj.offsetHeight 指 obj 控件自身的绝对高度,不包括因 overflow 而未显示的部分,也就是其实际占据的高度,整型,单位像素。

    scrollTop 是指当前容器顶部向下滚动时,顶部溢出的高度。

  4. 代码如下:

HTML:

<div class="container">
    <ul>
        <li class="moveDiv">1</li>
        <li class="moveDiv">2</li>
        <li class="moveDiv">3</li>
        <li class="moveDiv">4</li>
    </ul>
</div>

JS:

var moveBtns = document.querySelectorAll(".moveDiv");
$.each(moveBtns,function(index,value){
	value.addEventListener("touchstart",function(e){
	    if (drag0bj.parNode != null)
		return false;
		e = e || event;
		//触摸事件的默认是滚动页面,在此取消默认滚动
		e.preventDefault();
		drag0bj.parNode = this.parentNode.parentNode;
		drag0bj.xy = getXY(drag0bj.parNode);
		drag0bj.parNode.style.position = "absolute";
		drag0bj.parNode.style.top = drag0bj.xy.isTop + "px";
		drag0bj.parNode.style.width = drag0bj.xy.widthSet + "px";
		drag0bj.parNode.style.borderTop = "1px solid #E5E5E5";
		drag0bj.parNode.style.borderColor = "#363C62";
		drag0bj.parNode.style.opacity = "0.6";
		//创建一个临时空白li
		var om = document.createElement("li");
		drag0bj.otemp = om;
		om.style.width = drag0bj.xy.widthSet + "px";
		om.style.height = drag0bj.xy.heightSet + "px";
		om.style.borderTop = "1px dashed #363C62";
		om.style.borderBottom = "1px dashed #363C62";
		drag0bj.parNode.parentNode.insertBefore(om,drag0bj.parNode);
		dialogScrollHeight = dialog.scrollHeight;
		return false;
	    });
	value.addEventListener("touchmove",function(e){
	    e = e || event;
	    if (drag0bj.parNode != null) {
		querySelectorFn(".indicatorDialog").style.position = "fixed";
		var indiListTop = querySelectorFn("body").clientHeight;
		var d2 = querySelectorFn(".indicatorDialog").clientHeight;
		var d3 = querySelectorFn(".indicatorDialog").scrollTop;
		drag0bj.parNode.style.top = (d2 - (indiListTop - e.touches[0].clientY) - drag0bj.xy.heightSet/2 + d3) + "px";
		createTmpl(e);
		//当用户拖到顶部或底部时,自动滚动页面
		scrollPage(d3);
	    };
	});
	value.addEventListener("touchend",function(e){
	    e = e || event;
	    if (drag0bj.parNode != null) {
		$(".indicatorDialog").stop();//松开触摸时,停止滚动
		querySelectorFn(".indicatorDialog").style.position = "";
		drag0bj.otemp.parentNode.insertBefore(drag0bj.parNode,drag0bj.otemp);
		drag0bj.parNode.style.position = "";
		drag0bj.parNode.style.borderTop = "";
		drag0bj.parNode.style.borderColor = "#E5E5E5";
		drag0bj.otemp.parentNode.removeChild(drag0bj.otemp);
		drag0bj.parNode.style.opacity = "1";
		drag0bj = {};
		moveTimes = [];
	    };
	});
});	

var scrollPage = function(d3){
	var gapToBottom = dialog.clientHeight - drag0bj.parNode.offsetTop; //到底部的距离
	var pageHeight = dialog.scrollTop + dialog.clientHeight;
	var gapToTop = drag0bj.parNode.offsetTop - dialog.scrollTop;//到顶部的距离
	var scroll = function(scrollValue){
		var curTime = new Date().getTime();
		moveTimes.push(curTime);
		if((moveTimes[moveTimes.length - 1] - moveTimes[0]) > 800){
			$(".indicatorDialog").animate({
				scrollTop: scrollValue
			},"500");
			moveTimes = [];
		}
	}
	//向上滚动
	if (gapToTop < 50) {
	    scroll(d3 - 60);
	    return;
	};
	//向下滚动
	if (gapToBottom < 50 && pageHeight < dialogScrollHeight)
	    scroll(d3 + 60);
}

//获取拖动元素的宽高和距离屏幕顶的偏距
var getXY = function(e){
    var a = new Array();
    var pTop = e.offsetParent.offsetTop;//父级标签的top值
    var t = e.offsetTop; //e距离上方或上层控件的位置top值
    var w = e.offsetWidth;
    var h = e.offsetHeight;
    //indicatorDialog元素滚动时,距离弹出页面的top值会改变,
    //这样可以防止计算li元素top值的偏差
    var d3 = querySelectorFn(".indicatorDialog").scrollTop;
    a.topSet = t + pTop - d3;
    a.widthSet = w;
    a.heightSet = h;
    a.isTop = t;
    return a;
}
//判断拖动的li元素相对于其他li元素的位置
var inner = function(o, e) {
    var a = getXY(o);
    if (e.touches[0].clientY > a.topSet && e.touches[0].clientY < (a.topSet + a.heightSet)) {
        if (e.touches[0].clientY < (a.topSet + a.heightSet / 2))
            return 1;
        else
            return 2;
    } else
        return 0;
}
//移动模块后,创建新li块填充新元素
var createTmpl = function(e){
    var moveBtns = querySelectorFn(".indicatorListTemplate").getElementsByTagName("li");
    for (var i = 0; i < moveBtns.length; i++) {
        if (moveBtns[i] == drag0bj.parNode)
            continue;
        //忽略被删除后隐藏的li元素
        if (moveBtns[i].style.display == "none")
            continue;
        var b = inner(moveBtns[i],e);
        if (b == 0)
            continue;
        //1:UP ,2:DOWN
        if (b == 1)
            moveBtns[i].parentNode.insertBefore(drag0bj.otemp,moveBtns[i]);
        else{
            if (moveBtns[i].nextElementSibling == null || moveBtns[i].nextSibling == null)
	        moveBtns[i].parentNode.appendChild(drag0bj.otemp);
	    else
	        moveBtns[i].parentNode.insertBefore(drag0bj.otemp,moveBtns[i]);
        }
        return;
    };
}


你可能感兴趣的:(移动前端开发,元素拖动)