>  기사  >  웹 프론트엔드  >  JavaScript는 PC 웹 페이지에서 드래그 앤 드롭 효과를 구현합니다_javascript 기술

JavaScript는 PC 웹 페이지에서 드래그 앤 드롭 효과를 구현합니다_javascript 기술

WBOY
WBOY원래의
2016-05-16 15:10:551517검색

몇 년 전 저는 부동산 웹사이트 프로젝트의 디자인과 개발에 참여했는데, 프로젝트 매니저의 요구 사항이 상대적으로 높기 때문에 부동산의 우수한 기능을 많이 언급했습니다. 다른 사람들의 우수한 디자인과 아이디어를 수집하고 싶었고, 그 당시의 디자인 초안과 기능 구현은 단순히 변경만 반복되었습니다. 오늘 얻은 좋은 효과는 다음 날로 미루어야 할 수도 있습니다. 그 얘기는 하지말고 오늘 설명드릴 사건에 대해서 얘기해보겠습니다.(광고는 전혀 의심되지 않습니다.) 약간의 광고비?), 제품 관리자가 특히 좋아하는 기능이 하나 있는데, 바로 다음과 같습니다.

이것은 현재 효과이며, 약간의 변경이 있을 수 있습니다. 원래 효과는 내부의 그림을 상하좌우로 드래그할 수 있고, 그러면 집에 표시되는 건물 번호도 그림과 함께 이동한다는 것입니다. time,js 능력이 부족해서 프로젝트 매니저의 요구사항을 충족하지 못했는데 나중에 프로젝트 매니저가 이 효과를 거부하고 다른 효과로 교체했습니다

프로젝트 매니저가 이런 효과를 원하지 않았음에도 불구하고, 그 당시 제 마음에 뭉클하게 남아서 지금도 잊혀지지 않습니다.

좋아, 이것이 오늘 이 블로그를 쓰는 나의 원래 의도입니다. 이런 종류의 드래그 효과를 얻고 싶지만 그것을 달성하는 방법을 모르는 학생들에게 아이디어를 제공할 수 있기를 바랍니다. 물론 드래그 앤 드롭을 구현하는 방법은 다양합니다. 여기서는 JavaScript로 한 가지 방법만 소개하고 그 원리를 천천히 이해하겠습니다!

자, 농담은 끝났습니다. 우선 드래그가 무엇인지 이해해야 합니다. 여러분도 알고 있고 저도 알고 있지만 그래도 설명하고 싶습니다.

드래그 앤 드롭은 마우스를 사용하여 페이지에서 드래그할 수 있습니다. 정확한 설명은 마우스를 컨테이너로 이동한 다음 마우스를 놓지 않도록 주의하세요. 그런 다음 마우스를 놓으면 컨테이너가 마우스를 따라갈 수 있습니다. 실제 예는 테이블 위에 상자가 있는 경우입니다. 상자. 손이 멈추면 상자가 멈춥니다. 치우세요. 상자가 움직이지 않습니다. 헤헤, 이해해요!

위 내용이 너무 말도 안된다고 생각하지 마세요. 여기서 많은 정보를 얻을 수 있습니다. 요약은 다음과 같습니다.

드래그 = 마우스 다운 + 마우스 이동 + 마우스 업

이렇게 드래그 앤 드롭 작업이 완료되었습니다. 그런데 이것이 드래그 앤 드롭의 원리라는 것이 밝혀졌습니다. 드래그 앤 드롭을 구현하려면 위의 세 가지 동작을 자연스럽게 구현하여 드래그 앤 드롭 효과를 시뮬레이션할 수 있습니다. . 이는 JavaScript의 구문에 해당합니다.

다음 3가지 작업을 구현하면 됩니다.

onmousedown, onmousemove, onmouseup

구현된 코드는 다음과 같아야 합니다.

obj.onmousedown = function(ev){
   obj.onmousemove = function(ev){
 
   } ;
   obj.onmouseup = function(ev){
   
   };
   
}

다음 두 액션을 왜 작성해야 할까요? 잘 생각해 봅시다. 첫 번째 단계의 일반적인 아이디어는 다음 단계에서 마우스로 개체를 이동시키는 방법을 고려하는 것입니다. 아이디어는 아마도 다음과 같을 것입니다:

먼저 개체를 이동하려면 왼쪽 및 위쪽 값을 조작해야 하기 때문에 개체의 위치를 ​​지정해야 합니다. 그런 다음 마우스 변위 자체에 거리가 있어야 합니다. 마우스가 움직인 것을 알 수 있습니다. 그러면 개체에 이 거리가 부여됩니다. 개체가 마우스와 같은 거리로 이동합니까? ㅎㅎ 아이디어가 좀 있고 귀엽네요~ 이제 문제는 마우스의 거리를 어떻게 구하느냐 입니다. 더 알고 싶으시면 박스 모델을 검토해 보세요. 여기서는 다루지 않겠습니다. 많은 마스터들도 관련 블로그를 가지고 있습니다. 제가 사용하는 블로그는 다음과 같습니다.

설명: 파란색 상자는 화면의 너비와 높이, 두꺼운 검은색 상자는 브라우저의 가시 영역의 너비와 높이(브라우저 축소 효과), 얇은 검은색 상자는 마우스로 드래그할 개체입니다. , 그림과 같이 마우스 좌표를 얻으려면 event.clientX, event.clientY를 사용하여 얻을 수 있습니다.

일반적인 계산 원리는 아래 그림을 참조하세요.

설명: 왼쪽은 초기 위치, 오른쪽은 대상 위치, 원점은 마우스 위치, 큰 검은색 상자는 브라우저에 표시되는 너비, 작은 검은색 상자는 드래그 개체, 상태를 확인하세요. 개체를 대상 위치로 드래그하고 마우스의 최종 위치를 얻은 다음 마우스와 개체의 차이를 뺀 다음 개체의 위쪽 및 왼쪽 값에 할당합니다. 마우스의 위치 차이를 얻은 다음 초기 위쪽 및 왼쪽 값에 차이를 추가할 수도 있습니다. 두 번째 종류도 가능합니다. 직접 시도해 보세요.

 obj.onmousedown = function(ev){
  var ev = ev || event;
  var disX = ev.clientX - this.offsetLeft,disY = ev.clientY - this.offsetTop;
 
  document.onmousemove = function(ev){
    var ev = ev || event;
    obj.style.left = ev.clientX - disX + 'px';
    obj.style.top = ev.clientY - disY + 'px';
  };
  document.onmouseup = function(ev){
    var ev = ev || event;
    document.onmousemove = document.onmouseup = null;
  };
}

这里说明一下:onmousemove和onmouseup之所以用document对象而不用obj对象,是因为如果用obj对象,鼠标在obj内部还好,如果在obj外面的话,拖拽会很怪异,你也可以改成obj体会一下,最后我们在鼠标弹起的时候将事件都清空;

上面的基本拖拽就算完成了,但是细心的同学一定会问,如果页面上有文字的话,拖拽物体会将文字选中,这效果岂不是怪怪的,没错,这是因为拖拽的时候触发了浏览器的默认选择事件,所以,在拖拽的时候,我们要清除这个默认事件,那怎么清除呢?

下面给一个兼容性写法:

if(ev.stopPropagation){
   ev.stopPropagation();
}else{
  ev.cancelBubble = true; //兼容IE
}
//简写成
ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true;

将上面的代码放在onmousedown下,鼠标按下就清除浏览器默认事件,文字就不会被选中了,好了,一个简单的拖拽效果就完成了,当然你现在是看不到效果,之所以不给demo链接是为了让你自己试着写一写,这样印象更深刻,

好了,那问题又来了,到这里就这样完了吗?。。。。。。按本人的风格,当然没有,干货还在后面!

如果我想实现这样一个效果,就是这一个大的容器里面(可以是box,也可以是document),怎么样能让我们的拖拽对象不跑出去呢,换句话说,拖到边缘就拖不动了,耶,是不是很多人想要实现的效果,哈哈,我们看看实现的原理是什么:

现实生活中,一个物体在一个盒子里跑不出去,是因为有堵墙,那我们只要能模拟出这堵墙,就可以把物体框起来,那这堵墙要怎么做呢?我们可以换个思路,当拖拽对象拖到边缘的时候,比如说拖到右边,我们将它的left固定住,是不是就不能再往右了,因为left值不能再加了,那么拖到底部,同理我们将top值固定住,就不能再往下拖了,理解吗?

最终的结果就是如下:

//左侧
if(obj.offsetLeft <=0){
  obj.style.left = 0;
};
//右侧
if(obj.offsetLeft >= pWidth - oWidth){
  obj.style.left = pWidth - oWidth + 'px'; 
};
//上面
if(obj.offsetTop <= 0){
  obj.style.top = 0; 
};
//下面
if(obj.offsetTop >= pHeight - oHeight){
  obj.style.top = pHeight - oHeight + 'px'; 
};

说明:pWidth,pHeight 表示父级元素的宽高(这里是表示相对于父级的宽高限制),oWidth,oHeigt表示拖拽元素的宽高

最后,我将整个拖拽代码整理了一下:

/*
      参数说明:
      元素绝对定位,父级相对定位,如果父级为window,则可以不用
      传一个参数,表示父级为window,物体相对于window范围拖动
      传2个参数,则父级为第二个参数,物体相对于父级范围拖动
      参数为id值
    */
    function drag(obj,parentNode){
      var obj = document.getElementById(obj);
      if(arguments.length == 1){
        var parentNode = window.self; 
        var pWidth = parentNode.innerWidth,pHeight = parentNode.innerHeight;  
      }else{
        var parentNode = document.getElementById(parentNode);
        var pWidth = parentNode.offsetWidth,pHeight = parentNode.offsetHeight;
      }
      obj.onmousedown = function(ev){
        var ev = ev || event;
        var disX = ev.clientX - this.offsetLeft,disY = ev.clientY - this.offsetTop;
        var oWidth = obj.offsetWidth,oHeight = obj.offsetHeight;
         
        //阻止冒泡时间
        ev.stopPropagation &#63; ev.stopPropagation() : ev.cancelBubble = true;
       
         
        document.onmousemove = function(ev){
          var ev = ev || event;
          obj.style.left = ev.clientX - disX + 'px';
          obj.style.top = ev.clientY - disY + 'px';
           
          //左侧
          if(obj.offsetLeft <=0){
            obj.style.left = 0;
          };
          //右侧
          if(obj.offsetLeft >= pWidth - oWidth){
            obj.style.left = pWidth - oWidth + 'px'; 
          };
          //上面
          if(obj.offsetTop <= 0){
            obj.style.top = 0; 
          };
          //下面
          if(obj.offsetTop >= pHeight - oHeight){
            obj.style.top = pHeight - oHeight + 'px'; 
          };
        };
        document.onmouseup = function(ev){
          var ev = ev || event;
          document.onmousemove = document.onmouseup = null;
        };
      }
         
    }

说明:我这里处理的效果是,如果传一个参数,表示相对的对象是window对象,如果传2个参数,第一个是拖拽对象,第二个为相对父级

开篇就说了,搜房网的那个图片拖拽效果是我的一个心结,我写了一个类似的效果,供大家参考,因为自己没有买服务器,所以效果我就不展示了,直接把代码贴出来,供大家参考:

css:

<style>
.box{
  width:600px;
  height:400px;
  margin:50px auto;
  position:relative;
  overflow:hidden;
}
#box{
  width:1000px;
  height:800px;
  position:absolute;
  left:50%;
  top:50%;
  margin:-400px 0 0 -500px;
}
#pic{ width:800px; height:600px; background:url(images/pic1.jpg) no-repeat; position:absolute; left:100px; top:100px; }
#pic:hover{
  cursor:move;
}
</style>

html:

<div class="box">
    <div id="box">
      <div id="pic"></div>
    </div>
  </div>

javascript:

window.onload = function(){
     
    drag("pic","box");
    function drag(obj,parentNode){
      var obj = document.getElementById(obj);
      if(arguments.length == 1){
        var parentNode = window.self; 
        var pWidth = parentNode.innerWidth,pHeight = parentNode.innerHeight;  
      }else{
        var parentNode = document.getElementById(parentNode);
        var pWidth = parentNode.offsetWidth,pHeight = parentNode.offsetHeight;
      }
      obj.onmousedown = function(ev){
        var ev = ev || event;
        var disX = ev.clientX - this.offsetLeft,disY = ev.clientY - this.offsetTop;
        var oWidth = obj.offsetWidth,oHeight = obj.offsetHeight;
         
        //阻止冒泡时间
        ev.stopPropagation &#63; ev.stopPropagation() : ev.cancelBubble = true;
       
         
        document.onmousemove = function(ev){
          var ev = ev || event;
          obj.style.left = ev.clientX - disX + 'px';
          obj.style.top = ev.clientY - disY + 'px';
           
          //左侧
          if(obj.offsetLeft <=0){
            obj.style.left = 0;
          };
          //右侧
          if(obj.offsetLeft >= pWidth - oWidth){
            obj.style.left = pWidth - oWidth + 'px'; 
          };
          //上面
          if(obj.offsetTop <= 0){
            obj.style.top = 0; 
          };
          //下面
          if(obj.offsetTop >= pHeight - oHeight){
            obj.style.top = pHeight - oHeight + 'px'; 
          };
        };
        document.onmouseup = function(ev){
          var ev = ev || event;
          document.onmousemove = document.onmouseup = null;
        };
      }
         
    }
     
     
  }

效果完全是用的那个封装代码块,引用起来也挺方便,有人会问了,你这用的id获取DOM元素,一个页面只能用一次啊,如果页面多次使用呢,有道理,解决方案之一,那就命名不同的id呗,又不犯法,方案二,获取id的地方改成获取class,但是要注意的是,getElementsByClassName是获取的class集合,需要改写一下,这里我就不写了,有兴趣的同学自行改写一下,好了,到这里真的结束了!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.