js 实现 移动端 拖拽效果

点击下面 目录标题 在线预览效果

网页 head 部分

<!-- 禁止缩放 -->
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />

公共 js 部分

//提取非行间样式
function getStyle(obj,attr)
{
    if(obj.currentStyle)
    { return obj.currentStyle[attr];}
    else
    { return getComputedStyle(obj,false)[attr];}    
}

addEventListener 函数中  {passive: false} 参数说明:

Passive Event Listeners就是告诉前页面内的事件监听器内部是否会调用preventDefault函数来阻止事件的默认行为,以便浏览器根据这个信息更好地做出决策来优化页面性能。当属性passive的值为true的时候,代表函数(该监听器)内部不会调用 preventDefault 函数来阻止默认滑动行为;passive 的值为 false ,代表函数内部调用 preventDefault 函数来阻止默认滑动行为,代表函数内部调用 ,Chrome浏览器称这类型的监听器为被动(passive)监听器。目前Chrome主要利用该特性来优化页面的滑动性能,所以Passive Event Listeners特性当前仅支持 mousewheel/touch 相关事件。

手机端这里 touchStartEvent 函数中的对象使用 obj , 没有拖拽过快,obj 跟不上的问题。

移动端单个退拽元素

css 部分

body{height:2000px;}
.test{margin:150px; }
#ele{width:150px; height:150px;cursor: move;position: fixed;top:50px;color:#fff;box-sizing: border-box;z-index: 10;background:#2196f3;left:10px; font-size: 16px}

 js 部分

window.onload=function(ev){
    // 获取元素
    var Div=document.getElementById('ele');
    // 开始拖拽
    drag(Div,{passive: false});
}
 1 // 拖拽运动
 2 function drag(obj,passive){
 3 
 4     var lastX=0;
 5     var lastY=0;
 6     
 7     obj.addEventListener('touchstart',touchStartEvent,passive);
 8     // ev 为系统自带参数
 9     function touchStartEvent(ev)
10     {
11        var Ev=ev||event; // FF || IE 
12        var touch = Ev.targetTouches[0];
13        var disX=touch.clientX-parseInt(getStyle(obj,'left'));
14        var disY=touch.clientY-parseInt(getStyle(obj,'top'));
15 
16         //释放捕获,把鼠标事件 捕获到 当前文档指定的对象  针对IE 
17         if(obj.setCapture)
18         {
19                obj.addEventListener('touchmove',touchMoveEvent,passive);
20                obj.addEventListener('touchend',touchEndEvent,passive);
21             obj.setCapture();
22         }
23         else
24         {
25             // 手机端这里使用obj ,没有拖拽过快,obj 跟不上的问题
26                obj.addEventListener('touchmove',touchMoveEvent,passive);
27                obj.addEventListener('touchend',touchEndEvent,passive);
28         }
29            // 鼠标移动,函数上的 ev 参数是系统传过来的
30         function touchMoveEvent(ev)
31         {
32             var Ev=ev||event; // FF || IE 
33               var touch = Ev.targetTouches[0];
34             var l=touch.clientX-disX;
35             var t=touch.clientY-disY;
36         
37         
38            if(l>=document.documentElement.clientWidth-parseInt(getStyle(obj,'width')))
39            {
40                l=document.documentElement.clientWidth-parseInt(getStyle(obj,'width'));
41            }
42            else if(l<=0)
43            {  l=0;    }
44            
45            if(t>=document.documentElement.clientHeight-parseInt(getStyle(obj,'height')))
46            {
47                t=document.documentElement.clientHeight-parseInt(getStyle(obj,'height'));
48             }
49            else if(t<=0)
50            {  t=0;  }
51            
52            lastX=l;
53            lastY=t; // 当前的点赋给一个变量(上一个点)
54            obj.style.left=l+'px';
55              obj.style.top=t+'px'; //移动物体
56         }
57         // 鼠标抬起
58         function touchEndEvent()
59           {
60               obj.removeEventListener('touchmove',touchMoveEvent,passive);
61               obj.removeEventListener('touchend',touchEndEvent,passive);
62             if(obj.releaseCapture)
63             { obj.releaseCapture(); }
64 
65           } 
66         // 拖拽元素时,阻止页面跟随滚动问题
67         // 由于 {passive: false} ,如果不阻止默认事件,chrome 浏览器会有警告
68           Ev.preventDefault();
69         return false;
70     }
71 }
72 
73 //提取非行间样式
74 function getStyle(obj,attr)
75 {
76   if(obj.currentStyle)
77   { return obj.currentStyle[attr];}
78   else
79   { return getComputedStyle(obj,false)[attr];}    
80 }
View Code

html 部分

<div id="ele">单个退拽元素<br/>原生js<br/>不跟随页面滚动</div>
<p class="test">测试内容区域1</p>
<p class="test">测试内容区域2</p>
<p class="test">测试内容区域3</p>

移动端多个拖拽元素

css 部分

body{height:1500px;}
*{margin:0px;padding:0px;}
.test{margin:200px; }
#ele1,#ele2,#ele3{width:100px; height:100px;cursor: move;position: fixed;top:50px;color:#fff;box-sizing: border-box;z-index: 10;font-size: 14px}
#ele1{background:#2196f3;top:40px; }
#ele2{background:#ff5722;top:160px;}
#ele3{background:#08c80f;top:270px; }

js 部分

window.onload=function(){
    //获取拖拽的元素
    var ele1=document.getElementById('ele1');
    var ele2=document.getElementById('ele2');
    var ele3=document.getElementById('ele3');
    // 层级问题默认 ele1:1,ele2:2,ele3:3
    // 定义公共层级变量,3个定义的一样,这里取了第一个
    this.layer=parseInt(getStyle(ele1,'z-index'))
    // 调用拖拽函数
    drag(ele1,{passive: false});
    drag(ele2,{passive: false});
    drag(ele3,{passive: false});
}
 1 // 拖拽运动
 2 function drag(obj,passive){
 3       
 4     var lastX=0;
 5     var lastY=0;
 6 
 7     obj.addEventListener('touchstart',touchStartEvent,passive);
 8 
 9     function touchStartEvent(ev)
10     {
11        var Ev=ev||event; // FF || IE 
12        var touch = Ev.targetTouches[0];
13        var disX=touch.clientX-parseInt(getStyle(obj,'left'));
14        var disY=touch.clientY-parseInt(getStyle(obj,'top'));
15        // 层级问题,最后拖拽的在最上面,由于 zIndex 最大值是一个非常大的数,所以这里没有限制处理
16            obj.style.zIndex=window.layer=window.layer+1
17 
18         //释放捕获,把鼠标事件 捕获到 当前文档指定的对象  针对IE 
19         if(obj.setCapture)
20         {
21                obj.addEventListener('touchmove',touchMoveEvent,passive);
22                obj.addEventListener('touchend',touchEndEvent,passive);
23            obj.setCapture();
24         }
25         else
26         {
27                obj.addEventListener('touchmove',touchMoveEvent,passive);
28                obj.addEventListener('touchend',touchEndEvent,passive);
29         }
30            // 鼠标移动,函数上的 ev 参数是系统传过来的
31         function touchMoveEvent(ev)
32         {
33             var Ev=ev||event; // FF || IE 
34               var touch = Ev.targetTouches[0];
35             var l=touch.clientX-disX;
36             var t=touch.clientY-disY;
37         
38            if(l>=document.documentElement.clientWidth-parseInt(getStyle(obj,'width')))
39            {
40                l=document.documentElement.clientWidth-parseInt(getStyle(obj,'width'));
41            }
42            else if(l<=0)
43            {  l=0;    }
44            
45            if(t>=document.documentElement.clientHeight-parseInt(getStyle(obj,'height')))
46            {
47                t=document.documentElement.clientHeight-parseInt(getStyle(obj,'height'));
48             }
49            else if(t<=0)
50            {  t=0;  }
51            
52            lastX=l;
53            lastY=t; // 当前的点赋给一个变量(上一个点)
54            obj.style.left=l+'px';
55              obj.style.top=t+'px'; //移动物体
56         }
57         // 鼠标抬起
58         function touchEndEvent()
59           {
60               obj.removeEventListener('touchmove',touchMoveEvent,passive);
61               obj.removeEventListener('touchend',touchEndEvent,passive);
62             if(obj.releaseCapture)
63             { obj.releaseCapture(); }
64 
65           } 
66           // 拖拽元素时,阻止页面跟随滚动问题
67         // 由于 {passive: false} ,如果不阻止默认事件,chrome 浏览器会有警告
68         Ev.preventDefault()
69         return false;
70     }
71 }
View Code

 html  部分

<div id="ele1">多个退拽元素<br/>原生js<br/>不跟随页面滚动<br/>最后拖拽的在最上面</div>
<div id="ele2">多个退拽元素<br/>原生js<br/>不跟随页面滚动<br/>最后拖拽的在最上面</div>
<div id="ele3">多个退拽元素<br/>原生js<br/>不跟随页面滚动<br/>最后拖拽的在最上面</div>
<p class="test">测试内容区域</p>
<p class="test">测试内容区域2</p>
<p class="test">测试内容区域3</p>

单个退拽元素添加配置项

css 部分

/*body{height:1000px;}*/
*{margin:0px;padding:0px;}
.test{margin:150px; }
/*如果父元素不是body,建议手动指定 left top 值,如果不指定 默认 bottom:0; left:50( 我这里设置margin:50 原因); */
#warp{width:260px;height:260px;border: 1px #ccc solid;margin:50px; background: #fff;left:-20px;top:50px;z-index: 9;}
/*拖拽范围元素 层级要低于 拖拽元素层级*/
#ele{width:150px; height:150px;cursor: move;color:#fff;box-sizing: border-box;z-index: 10;font-size: 16px;background:#2196f3; }

js 部分

  配置参数:

top,bottom,left,right 默认值为 0 ,拖拽元素 距离 范围元素(默认body) 的距离
direction 拖拽方向,默认为任意方向,lr(左右) tb(上下)
parent:'warp', 为页面唯一元素,拖拽元素活动范围 元素,id 名称,例如 warp ,默认body整个页面
scroll:false 拖拽元素是否随 页面滚动 false 不随页面滚动,true 随页面滚动

// 当页面加载的时候----如果添加 onresize ,页面滚动,拖拽元素恢复初始值
window.onload=function(){
    // 配置选项
    var opt={
        top:0,
        bottom:0,
        left:20,
        right:10,
        parent:'warp', // 为页面唯一元素,id 名称,例如 warp ,默认body整个页面
        scroll:true // 拖拽元素是否随 页面滚动 false 不随页面滚动,true 随页面滚动
    }
    var obj=document.getElementById('ele');

    // 调用拖拽函数
    drag(obj,opt,{passive: false});
}
  1 // 拖拽运动
  2 function drag(obj,opt={},passive){
  3     // 默认配置选项
  4     var option={
  5         direction:'auto',//方向 lr(左右)  tb(上下)
  6         // 运动范围 默认父级边界
  7         top:0,
  8         bottom:0,
  9         left:0,
 10         right:0,
 11         //parent:'warp', // 为页面唯一元素,id 名称,例如 warp ,默认body整个页面
 12         scroll:false // 拖拽元素是否随 页面滚动 false 不随页面滚动,true 随页面滚动
 13     }
 14         // 合并对象参数
 15     Object.assign(option,opt)
 16       
 17     var lastX=0;
 18     var lastY=0;
 19     var parent_width=0,parent_height=0,parent_left=0,parent_top=0;
 20     var ele_position='fixed'
 21     if(option.scroll){
 22         ele_position='absolute'
 23     }else{
 24         // 如果不跟随页面滚动,并且元素父级不是body,父元素定位,
 25         if(option.parent)
 26             document.getElementById(option.parent).style.position='fixed'
 27     }
 28 
 29     // 设置元素的定位,需要放置获取 parent_* 值之前
 30     obj.style.position=ele_position
 31     
 32     if(option.parent){
 33         var parent_ele=document.getElementById(option.parent)
 34         parent_width=parent_ele.clientWidth;
 35         parent_height=parent_ele.clientHeight;
 36         parent_left=parent_ele.offsetLeft;
 37         parent_top=parent_ele.offsetTop;
 38     }else{
 39             if(option.scroll){
 40                 parent_width=document.documentElement.scrollWidth
 41                 parent_height=document.documentElement.scrollHeight
 42             }else{
 43                 parent_width=document.documentElement.clientWidth
 44                 parent_height=document.documentElement.clientHeight
 45             }
 46     }
 47 
 48     // 设置元素位置
 49     obj.style.left=option.left+parent_left+'px'
 50     obj.style.top=option.top+parent_top+'px'
 51 
 52     // 手指按下
 53     obj.addEventListener('touchstart',touchStartEvent,passive);
 54 
 55     function touchStartEvent(ev)
 56     {
 57        var Ev=ev||event; // FF || IE 
 58        var touch = Ev.targetTouches[0];
 59        var disX=0,disY=0;
 60 
 61        if(option.direction=="lr"){
 62                  disX=touch.clientX-parseInt(getStyle(obj,'left'));
 63        }else if(option.direction=="tb"){
 64                 disY=touch.clientY-parseInt(getStyle(obj,'top'));
 65        }else{
 66              disX=touch.clientX-parseInt(getStyle(obj,'left'));
 67              disY=touch.clientY-parseInt(getStyle(obj,'top'));
 68        }
 69 
 70        if(obj.setCapture)//设置事件捕获  针对IE
 71        {
 72             obj.addEventListener('touchmove',touchMoveEvent,passive);
 73                obj.addEventListener('touchend',touchEndEvent,passive);
 74             obj.setCapture();
 75        }else
 76        {
 77             obj.addEventListener('touchmove',touchMoveEvent,passive);
 78                obj.addEventListener('touchend',touchEndEvent,passive);
 79        }
 80            // 鼠标移动
 81         function touchMoveEvent(ev)
 82         {
 83                var Ev=ev||event; // FF || IE 
 84                var touch = Ev.targetTouches[0];
 85 
 86             var left=0,top=0,move_left=0,move_top=0
 87             if(option.direction=="lr"){
 88                    // 可移动的最大左边距离
 89                    move_left=parent_width-parseInt(getStyle(obj,'width'))-option.right+parent_left
 90                       if(left>=move_left){
 91                           left=move_left
 92                       }else if(left<=option.left+parent_left){
 93                           left=option.left+parent_left
 94                       }else{
 95                           left=touch.clientX-disX;
 96                       }
 97                       lastX=left;
 98                       obj.style.left=left+'px';
 99                
100                }else if(option.direction=="tb"){
101                    // 可以移动的最大上边距
102                    move_top=parent_height-parseInt(getStyle(obj,'height'))-option.top+parent_top
103                    if(top>=move_top){
104                     top=move_top
105                    }else if(top<=option.bottom+parent_top){
106                     top=option.bottom
107                    }else{
108                            top=touch.clientY-disY;
109                    }
110                    lastY=top; 
111                    obj.style.top=top+'px'; 
112                }else{
113                 left=touch.clientX-disX;
114                 top=touch.clientY-disY;
115             
116                 move_left=parent_width-parseInt(getStyle(obj,'width'))-option.right+parent_left
117                 move_top=parent_height-parseInt(getStyle(obj,'height'))-option.bottom+parent_top
118             
119                 if(left>=move_left){
120                           left=move_left
121                       }else if(left<=option.left+parent_left){
122                           left=option.left+parent_left
123                       }
124                       if(top>=move_top){
125                     top=move_top
126                     }else if(top<=option.bottom+parent_top){
127                     top=option.bottom+parent_top
128                     }
129 
130                 lastX=left;
131                 lastY=top; // 当前的点赋给一个变量(上一个点)
132                 obj.style.left=left+'px';
133                   obj.style.top=top+'px'; //移动物体
134                }
135         }
136         // 鼠标抬起
137         function touchEndEvent()
138           {
139             obj.addEventListener('touchmove',touchMoveEvent,passive);
140                obj.addEventListener('touchend',touchEndEvent,passive);
141             //释放事件捕获
142             if(obj.releaseCapture)
143             { obj.releaseCapture(); }
144 
145           } 
146         // 拖拽元素时,阻止页面跟随滚动问题
147         // 由于 {passive: false} ,如果不阻止默认事件,chrome 浏览器会有警告
148           Ev.preventDefault()
149         return false;
150     }
151 }
View Code

html 部分

<p>指定元素内拖拽,居左20px,居右10px</p>
<p>随页面滚动</p>
<div id="warp">指定元素内拖拽</div>    
<p class="test">测试内容区域</p>
<div id="ele">单个拖拽元素<br/>原生js<br/>添加配置选项</div>
<p>测试部分</p>
<p class="test">测试内容区域2</p>

 

posted @ 2022-12-16 16:06  柔和的天空  阅读(945)  评论(0编辑  收藏  举报