javascript鼠標(biāo)跟隨運動3種效果(眼球效果,蘋果菜單,方向跟隨)
運動除了直線運動和曲線運動兩種運動形式外,還有一種運動形式是鼠標(biāo)跟隨運動,而這種跟隨運動需要用到三角函數(shù)的相關(guān)內(nèi)容或者需要進(jìn)行比例運算。本文將以幾個小實例來介紹角度運動的相關(guān)內(nèi)容
眼球轉(zhuǎn)動
在很多網(wǎng)頁中,都存在著跟隨運動,比如眼球轉(zhuǎn)動。鼠標(biāo)在網(wǎng)頁中移動時,眼球也會跟著朝相應(yīng)方向轉(zhuǎn)動
上面是眼球轉(zhuǎn)動的示意圖,(x0,y0)是眼球的位置,而(x,y)是鼠標(biāo)的位置。設(shè)直線與垂直方向的夾角為a,假設(shè)圓心點坐標(biāo)為(0,0),可以得到以下公式
tan(a) = x/y = x0/y0
x0 = r*sin(a)
y0 = r*cos(a)
在mousemove事件中,可以很容易的得到鼠標(biāo)位置(x,y),由此求出夾角a,進(jìn)而可以求出眼球的位置
設(shè)左眼為ball1,右眼為ball2。左眼的圓心坐標(biāo)是(39,72),右眼的圓心坐標(biāo)是(106,68),眼球可以移動的半徑是12px
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> #test{position: absolute;top: 100px;left: 200px;} #ball1{position: absolute;top: 62px;left: 28px;} #ball2{position: absolute;top: 58px;left: 96px;} </style> </head> <body> <div id="test"> <img src="head.png" alt="body"> <img id="ball1" src="ball.png" alt="ball"> <img id="ball2" src="ball.png" alt="ball"> </div> <script> //聲明腦袋的默認(rèn)偏移 var offsetLeft = test.offsetLeft; var offsetTop = test.offsetTop; //聲明左眼夾角a1、右眼夾角a2 var a1,a2; //聲明左眼圓心(X1,Y1)、右眼圓心(X2,Y2) var X1 = 38,Y1 = 72,X2 = 106,Y2 = 68; //聲明半徑 var R = 12; document.onmousemove = function(e){ e = e || event; //獲取鼠標(biāo)坐標(biāo) var x = e.clientX; var y = e.clientY; //更新夾角a1、a2 a1 = Math.atan2(x-X1-offsetLeft,y-Y1-offsetTop); a2 = Math.atan2(x-X2-offsetLeft,y-Y2-offsetTop); //更新左眼、右眼的left、top值 ball1.style.left = R*Math.sin(a1) + X1 -10 + 'px'; ball1.style.top = R*Math.cos(a1) + Y1 -10+ 'px'; ball2.style.left = R*Math.sin(a2) + X2 -10 + 'px'; ball2.style.top = R*Math.cos(a2) + Y2 -10 + 'px'; } </script> </body> </html>
蘋果菜單
蘋果菜單中也存在著鼠標(biāo)跟隨運動,與鼠標(biāo)距離越近的菜單項的寬高越大,越遠(yuǎn)則寬高越小
鼠標(biāo)坐標(biāo)可以通過mousemove事件中的clientX和clientY獲得。菜單項的坐標(biāo)其實是已知項。而鼠標(biāo)坐標(biāo)與菜單項的距離就是要求的距離,而距離與菜單項的寬高成反比
[注意]不能夠?qū)⒃氐淖远x屬性命名為x,因為x已經(jīng)被瀏覽器使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> body{margin: 0;} #test{position: absolute;bottom:0;width: 100%;text-align: center;} img{width: 64px;height: 64px;} </style> </head> <body> <div id="test"> <img id="img1" src="img/1.png"> <img src="img/2.png"> <img src="img/3.png"> <img src="img/4.png"> <img src="img/5.png"> </div> <script> //聲明菜單項的寬高值 var offsetWidth = img1.offsetWidth; var offsetHeight = img1.offsetHeight; //聲明外層盒子的left、top值 var offsetLeft = test.offsetLeft; var offsetTop = test.offsetTop; //獲取菜單項 var imgs = test.getElementsByTagName('img'); document.onmousemove = function(e){ e = e || event; //更新鼠標(biāo)位置 var x = e.clientX; var y = e.clientY; for(var i = 0; i < imgs.length; i++){ //獲取菜單項的坐標(biāo) imgs[i].x0= imgs[i].offsetLeft+offsetLeft+imgs[i].offsetWidth/2; imgs[i].y0 = imgs[i].offsetTop + offsetTop + imgs[i].offsetHeight/2; //更新鼠標(biāo)與菜單項的距離 imgs[i].len =Math.sqrt((x-imgs[i].x0)*(x-imgs[i].x0) + (y-imgs[i].y0)*(y-imgs[i].y0)); //限制范圍 if(imgs[i].len > 150){ imgs[i].len = 150; } //更新菜單項的寬高 imgs[i].style.width = (1-imgs[i].len/300)*2*offsetWidth + 'px'; imgs[i].style.height = (1-imgs[i].len/300)*2*offsetHeight + 'px'; } } </script> </body> </html>
方向跟隨
有許多網(wǎng)頁都有方向跟隨的效果。鼠標(biāo)從哪個方向移入,元素就跟著從哪個方向移入。鼠標(biāo)從哪個方向移出,類似地,元素也跟著從哪個方向移出
移入移出的運動效果使用勻速直線運動即可,這里主要需要判斷方向
由示意圖中所示,可以把一個正方形的元素分成(上-右、上-左、左-上、左-下、下-右、下-左、右-上、右-下)這8個部分,每個部分是一個等腰直角三角形,當(dāng)元素進(jìn)入某個區(qū)域時,橫線前面的方向就表示元素的方向
假設(shè)正方形的中心坐標(biāo)為(x0,y0),動態(tài)元素(move)進(jìn)入時的坐標(biāo)為(x,y),以這兩個坐標(biāo)組成的直線與水平正方向的直線的夾角作為基準(zhǔn)角,假設(shè)為a,則通過確定夾角a的范圍,可以確定動態(tài)元素(move)進(jìn)入的方向
-45<a<45時,進(jìn)入方向為右
45<a<135時,進(jìn)入方向為上
a>135或a<-135時,進(jìn)入方向為左
-135<a<-45時,進(jìn)入方向為下
確定好動態(tài)元素(move)進(jìn)入的方向后,需要根據(jù)方向,將動態(tài)元素(move)瞬間變換到對應(yīng)的位置。然后,動態(tài)元素(move)進(jìn)行勻速直線運動,最終停止在與靜態(tài)元素(test)重合的位置
動態(tài)元素(move)移出靜態(tài)元素(test)的范圍時,要注意的是,并不會觸發(fā)靜態(tài)元素(test)的mouseout事件。因為,此時鼠標(biāo)一直處于動態(tài)元素(move)上。所以,觸發(fā)的是動態(tài)元素(move)的mouseout事件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> #box{overflow: hidden;position: relative;left: 100px;top: 100px;height: 100px;width: 300px;} .test{width: 100px;height: 100px;position: absolute;font:20px/100px '宋體';text-align: center;} </style> </head> <body> <div id="box"> <div class="test" style="top: 0px;left: 0px;background-color: pink;">1</div> <div class="test" style="top: 0px;left: 100px;background-color: lightcoral;">2</div> <div class="test" style="top: 0px;left: 200px;background-color: lightgreen;">3</div> <div id="move" style="width: 100px;height: 100px;background-color: lightblue;position: absolute;top: -100px;left: -100px;"></div> </div> <script> var tests = box.getElementsByTagName('div'); for(var i = 0; i < tests.length; i++){ tests[i].onmouseover = fn; } //鼠標(biāo)移出動態(tài)元素(move)時,再將fn()函數(shù)置于所有靜態(tài)元素上 move.onmouseout = fn; function fn(e){ e = e || event; //阻止冒泡 if(e.stopPropagation){ e.stopPropagation(); }else{ e.cancelBubble = true; } for(var i = 0; i < tests.length; i++){ tests[i].onmouseover = fn; } var _this = this; //鼠標(biāo)移入動態(tài)元素(move)時,將靜態(tài)元素上的mouseover事件置空 move.onmouseover = function(){ move.innerHTML = _this.innerHTML; _this.onmouseover = null; } //聲明坐標(biāo) var x = e.clientX; var y = e.clientY; //聲明靜態(tài)元素(test)左上角坐標(biāo)(相對于父級) var x11 = this.offsetLeft; var y11 = this.offsetTop; //聲明靜態(tài)元素(test)中心點坐標(biāo)(相對于父級) var x10 = x11 + this.offsetWidth/2; var y10 = y11 + this.offsetHeight/2; //聲明靜態(tài)元素(test)左上角坐標(biāo)(相對于文檔) var x21 = this.parentNode.offsetLeft + x11; var y21 = this.parentNode.offsetTop + y11; //聲明靜態(tài)元素(test)中心點坐標(biāo)(相對于文檔) var x20 = x21 + this.offsetWidth/2; var y20 = y21 + this.offsetHeight/2; //聲明靜態(tài)元素寬高 var height = this.offsetHeight; var width = this.offsetWidth; //聲明并計算夾角 var a = Math.atan2(y20-y,x-x20)*180/Math.PI; //聲明并計算方向 var dir; if(a > -45 && a < 45){ dir = 'right'; }else if(a > 45 && a < 135){ dir = 'top'; }else if(a > -135 && a < 45){ dir = 'bottom'; }else{ dir = 'left'; } //鼠標(biāo)移入時 if(e.type == 'mouseover'){ //更新動態(tài)元素(move)的初始位置 //移動動態(tài)元素(move)直到完全覆蓋靜態(tài)元素(test) if(dir == 'right'){ move.style.left = x10 + width/2 + 'px'; move.style.top = y10 - height/2 + 'px'; fnMove(move,'left',x11) }else if(dir == 'top'){ move.style.left = x10 - width/2 + 'px'; move.style.top = y10 - height/2 - height + 'px'; fnMove(move,'top',y11) }else if(dir == 'left'){ move.style.left = x10 - width/2 - width + 'px'; move.style.top = y10 - height/2 + 'px'; fnMove(move,'left',x11) }else{ move.style.left = x10 - width/2 + 'px'; move.style.top = y10 - height/2 + height + 'px'; fnMove(move,'top',y11) } } if(e.type == 'mouseout'){ //鼠標(biāo)移出時 if(dir == 'right'){ fnMove(move,'left',x11 + width); }else if(dir == 'top'){ fnMove(move,'top',y11 - height); }else if(dir == 'left'){ fnMove(move,'left',x11 - width); }else{ fnMove(move,'top',y11 + height); } } } function getCSS(obj,style){ if(window.getComputedStyle){ return getComputedStyle(obj)[style]; } return obj.currentStyle[style]; } function fnMove(obj,attr,target){ var H = obj.offsetHeight; if(obj.timer) return; var cur = parseFloat(getCSS(obj,attr)); if(target > cur){ var step = H/4; }else{ var step = -H/4; } obj.timer = setInterval(function(){ cur = parseFloat(getCSS(obj,attr)); cur = cur + step; if((cur -target) * step >= 0){ cur = target; } obj.style[attr] = cur + 'px'; if(cur == target){ clearInterval(obj.timer); obj.timer = 0; } },20); } </script> </body> </html>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Javascript調(diào)試之console對象——你不知道的一些小技巧
這篇文章主要總結(jié)了console對象的一些有用的方法,非常不錯,具有參考借鑒價值,需要的朋友參考下吧2017-07-07document.compatMode的CSS1compat使用介紹
這篇文章主要介紹了document.compatMode的CSS1compat使用,需要的朋友可以參考下2014-04-04JavaScript兩種axios取消請求方式小結(jié)
本文主要介紹了JavaScript兩種axios取消請求方式小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03js print打印網(wǎng)頁指定區(qū)域內(nèi)容的簡單實例
下面小編就為大家?guī)硪黄猨s print打印網(wǎng)頁指定區(qū)域內(nèi)容的簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-11-11微信小程序控制臺提示warning:Now you can provide attr "wx:key" for a "w
這篇文章主要介紹了微信小程序控制臺提示warning:Now you can provide attr "wx:key" for a "wx:for" to improve performance解決方法,簡單分析了wx:for警告提示相關(guān)解決方法,需要的朋友可以參考下2019-02-02ES6 javascript中class類的get與set用法實例分析
這篇文章主要介紹了ES6 javascript中class類的get與set用法,結(jié)合具體實例形式分析了ES6中類的get與set關(guān)鍵字使用方法,需要的朋友可以參考下2017-10-10javascript實現(xiàn)字符串反轉(zhuǎn)的方法
這篇文章主要介紹了javascript實現(xiàn)字符串反轉(zhuǎn)的方法,實例分析了javascript實現(xiàn)字符串反轉(zhuǎn)的技巧,需要的朋友可以參考下2015-02-02