首頁 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脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++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,對於普通

國產FPS新王炸! 《三角洲行動》大戰場超乎預期 國產FPS新王炸! 《三角洲行動》大戰場超乎預期 Mar 07, 2024 am 09:37 AM

《三角洲行動》將在今日(3月7日)開啟一場名為「代號:ZERO」的大規模PC測試。而在上週末,這款遊戲在上海舉辦了一次線下快閃體驗活動,17173也有幸受邀參與其中。這次測試距離上一次僅相隔四個多月,不禁讓我們好奇,在這麼短的時間內,《三角洲行動》將會帶來哪些新的亮點與驚喜?四個多月前,我已先行在線下品鑑會和首測版本中體驗了《三角洲行動》。當時,遊戲僅開放了「危險行動」這個模式。然而,《三角洲行動》在當時的表現已然令人矚目。在各大廠商紛紛湧向手遊市場的背景下,如此一款與國際水準相媲美的FPS

國風硬核武俠動作遊戲《乂聞錄:輪迴》今日開啟線上試玩 國風硬核武俠動作遊戲《乂聞錄:輪迴》今日開啟線上試玩 Feb 06, 2024 pm 06:00 PM

國風硬核武俠動作遊戲《乂聞錄:輪迴》於今日開啟線上試玩。這是一款多平台的硬核武器俠動作單機遊戲,融合了中國傳統文化元素,遊戲中玩家扮演一位阻止世界災變,還一方安定祥和的武俠角色。官方聲稱,玩家可以透過精美的美術場景和生動的故事來闡述武俠武術文化的價值,挖掘和展示武俠文化的內涵與精神,同時體驗一趟奇妙之旅。根據開發者介紹,團隊的設計初衷為了讓玩家可以更好地體驗到武術的風采,團隊研究了大部分中國武術的各種流派和技巧,並將它們逼真地呈現在遊戲中。玩家可以學習或遇到一些敵人使用多種技能和招式,如太極拳、刀法和

See all articles