首页 web前端 js教程 javascript实现PC网页里的拖拽效果_javascript技巧

javascript实现PC网页里的拖拽效果_javascript技巧

May 16, 2016 pm 03:10 PM
javascript pc 拖拽

几年前,我参与设计开发一个房产网的项目,我负责前端工作,由于项目经理要求比较高,参考了很多房产类网站比较优秀的功能,想把别人比较优秀的设计和想法集合到一起,那时的设计稿和功能实现,简直就是改了又改,今天做好的一个很好的效果,可能第二天就要推到重来,算了,不说这些了,还是说说我们今天要讲解的案例吧,不知道大家访问过搜房网没有(完全没有做广告之嫌,搜房网,可以给点广告费不),其中有一个功能产品经理特别喜欢,那,就是下面的这个:

这是现在的效果,可能改了一些,原来的效果是,里面的这张图是可以上下左右拖动的,然后房子上面的显示的楼栋号,也跟着图片一起移动,当时js能力还不行,未能实现项目经理的要求,不过后来项目经理又把这个效果推掉了,换了另外的一个效果

尽管项目经理不想要这个效果了,但是当时就在我心里留下了一个节,到今天都忘不了这个梗。

好了,这就是我今天想写这篇博客的初衷,希望能给想实现这类拖拽效果,但是不知道该怎么去实现的同学,提供一种思路,不给青春留遗憾,当然实现拖拽的方法有很多,这里就只介绍JavaScript中的一种方法,慢慢体会一下其中的原理!

好了,梗也说完了,开始正题,我们先要明白,拖拽到底是一个什么东西,你也知道,我也知道,但是我还是想来描述一下:

拖拽就是一个容器,你用鼠标可以在页面上拖着到处跑,废话,精确的描述应该是,鼠标移到容器上,然后鼠标按下去,注意要按着不放,然后拖动鼠标,容器能跟着鼠标跑,松开鼠标,容器就停在那里不动了,现实中的例子就是桌子上有一个盒子,我用手放在盒子上,然后移动盒子,手停盒子停,手拿开,盒子不动了,嘻嘻,都懂了哈!

别以为上面说了一堆的废话,我们可以从中得到很多的信息,总结如下就是:

拖拽 = 鼠标按下 + 鼠标移动 + 鼠标弹上

这样就完成了一个拖拽任务,好了,原来这就是拖拽的原理,想实现拖拽,自然实现上面的3个动作,便可以模拟拖拽效果,好,对应JavaScript中的语法就是需要实现这3个动作:

onmousedown , onmousemove , onmouseup

 实现的代码就应该是:

obj.onmousedown = function(ev){
   obj.onmousemove = function(ev){
 
   } ;
   obj.onmouseup = function(ev){
   
   };
   
}
登录后复制

为什么后面2个动作要写的里面,好好回味一下,好了,第一步的大概思路就有了,下一步就需要考虑怎么让物体跟着鼠标一起移动,思路大概是这样的:

首先物体是需要决定定位的,因为我们需要操作它的left和top值,才能让它移动,然后就是要考虑鼠标了,鼠标位移,本身就会有一个距离,如果我们知道鼠标移动了多远,然后把这个距离给物体,那物体是不是也和鼠标一样,移动了相同的距离,这不就实现拖拽了吗?哈哈,思路一点点有,感觉萌萌哒~ 现在的问题就是怎么获取鼠标的距离,如果需要深入了解,请复习一下盒子模型,这里我就不说了,很多大神也有相关的博客,我用一张图表示一下:

说明:蓝色框为屏幕宽高,黑色粗框为浏览器可视区宽高(浏览器缩小效果),黑色细框为鼠标要拖拽的对象,如图可知,获取鼠标的坐标,可以用event.clientX,event.clientY来获取,哦了;

计算的大致原理可以参照下图:

说明:左边为初始位置,右边为目标位置,原点为鼠标位置,大黑框为浏览器可视宽度,小黑框为拖拽对象,看拖拽对象到目标位置的状态,获取鼠标的最终位置,再减去鼠标距离对象的差值,再赋值给对象的top,left值,也可以获取鼠标的位置差值,再用初始的top,left值加上差值,我们采用第一种,第二种也可以,自己去试一下:

 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

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前 By 尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何在Windows PC上解决接入点临时满错误 如何在Windows PC上解决接入点临时满错误 Mar 16, 2024 pm 03:19 PM

当连接到Windows11/10PC上的Wi-Fi路由器或移动热点时,如果遇到错误的“接入点暂时满”的问题,这通常是由于网络过载或连接设备数量过多引起的。为了解决这个问题并成功连接到互联网,您可以尝试以下方法:1.等待一段时间,让其他设备断开连接后再尝试连接。2.重启Wi-Fi路由器或移动热点,以便清除网络缓存并重新分配IP地址。3.确保您的PC的Wi-Fi适配器驱动程序是最新的,可以通过设备管理器来检查更新。4.尝试在不同的时间连接,避开高峰时段可能会有更好的连接机会。5.考虑增AccessP

Windows PC持续引导至BIOS[修复程序] Windows PC持续引导至BIOS[修复程序] Mar 11, 2024 am 09:40 AM

如果您的WindowsPC频繁进入BIOS界面,这可能会导致使用困难。每次开机都被BIOS屏幕所困扰,重新启动也无济于事。如果您正面临这个问题,那么本文中提供的解决方案将会对您有所帮助。为什么我的电脑一直在BIOS中启动?您的电脑在BIOS模式下频繁重新启动可能涉及多种原因,比如启动顺序设置不当、SATA电缆受损、连接不牢固、BIOS配置错误或是硬盘故障等。修复WindowsPC持续引导进入BIOS的问题如果您的WindowsPC不断引导至BIOS,请使用以下修复程序。检查您的引导顺序重新拔插内

如何在Windows PC上使用Samsung Flow 如何在Windows PC上使用Samsung Flow Feb 19, 2024 pm 07:54 PM

SamsungFlow是一个方便实用的工具,可以让您轻松地连接Galaxy手机到WindowsPC。通过SamsungFlow,您可以方便地在设备之间共享内容,同步通知,镜像智能手机等。本文将介绍如何在Windows电脑上使用SamsungFlow。如何在WindowsPC上使用智能手机流要使用SamsungFlow连接WindowsPC和GalaxyPhone,需要确保您的Galaxy智能手机和平板电脑运行Android7.0或更高版本,以及您的WindowsPC运行Windows10或更高版

如何一次将所有OneDrive文件下载到PC 如何一次将所有OneDrive文件下载到PC Feb 19, 2024 pm 06:51 PM

本文将教您如何一次性将所有OneDrive文件下载到您的PC。OneDrive是一个强大的云存储平台,方便用户随时随地访问其文件。有时,用户可能需要在本地备份文件或离线访问。继续阅读以了解如何轻松完成这一操作。如何一次将所有OneDrive文件下载到PC?按照以下步骤一次性将所有OneDrive文件下载到您的WindowsPC:启动Onedrive并导航到我的文件。在OneDrive上上传的所有文件都将在此处提供。按CTRL+A选择所有文件,或选中复选框中所有项目的切换选择。单击顶部的下载选项,

低价Chrome主机历险记:装不了黑苹果,算是合格的PC 低价Chrome主机历险记:装不了黑苹果,算是合格的PC Jul 11, 2024 pm 04:38 PM

说起来我们的洋垃圾系列也已经做了很多期了,不过之前大多是手机和组装PC,前者可玩性一般,后者则是不确定性拉满。比如我们上次花300装的电脑,现在已经进入不停掉驱动的状态。不过,“捡破烂”这种事情本就如此,风险与收益并存才是常态。像这次我“捡”回来的华硕ChromeBox,本来是想将其制作成一部Macmini(伪),但是在折腾的过程中遇到了许多意料之外的问题,没能达成预定目标。我最终只能退而求其次,选择给它刷个Windows。虽然刷黑苹果的尝试倒在了最后一步,不过整个过程中获得了很多乐趣。而且作为

我花300块组装的电脑,成功跑通了本地大模型 我花300块组装的电脑,成功跑通了本地大模型 Apr 12, 2024 am 08:07 AM

如果说2023年是大家公认的AI元年,那么2024年很可能就是AI大模型普及的关键一年。在过去的一年中,大量的AI大模型、大量的AI应用横空出世,Meta、Google等厂商也开始面向民众推出自己的在线/本地大模型,类似于“AI人工智能”这样遥不可及的概念,就这样突然来到了人们身边。如今人们在生活中越来越多地接触到人工智能,如果你仔细分辨,你会发现,你所能接触到的各类AI应用,他们几乎都部署在“云端”上。如果想要搭建一台本地运行大模型的设备,那么硬件都是售价5000元以上的全新AIPC,对于普通

PC反复开机和关机,但没有显示 PC反复开机和关机,但没有显示 Mar 04, 2024 am 09:47 AM

当您的WindowsPC出现反复开关并且没有显示时,可能是由硬件故障引起的。这种问题通常与电源问题有关。以下是一些解决方案,可以帮助您解决这种情况。当我的电脑反复开机和关机时,意味着什么?电脑频繁开关可能是硬件故障的迹象,电源问题也有可能引起此现象。CPU和RAM是最常见导致此问题的硬件部件。PC反复开机和关机,但没有显示如果您的电脑打开和关闭,但没有显示,以下建议将帮助您。断开并重新连接电源线将您的计算机连接到另一个墙上插座启动您的笔记本电脑没有电池重置cmos重新拔插内存重新拔插CPUPSU

IDC:2023 全球 PC 显示器出货量下降 8.6%,2024 将温和复苏 IDC:2023 全球 PC 显示器出货量下降 8.6%,2024 将温和复苏 Mar 23, 2024 pm 04:06 PM

本站3月22日消息,根据市场调查机构IDC公布的最新报告,2023年第4季度全球PC显示器出货量为3190万台,同比增长3.8%,略高于IDC此前预测的3.2%。第四季度,主要细分市场都出现了增长,其中消费市场的增长速度超过了商用市场。增长不是来自低端市场,而是来自主流和高端价位市场。2023年上半年PC显示器出货量下降了17.4%,让2023年全年出货量下降了8.6%。IDC表示2023年,游戏显示器占显示器总出货量的近16%。游戏PC出货量的减少释放了更多的预算,而入门到中级显示器领域的激烈

See all articles