JavaScript實(shí)現(xiàn)類似拉勾網(wǎng)的鼠標(biāo)移入移出效果
先上效果圖(gif自己錄制的,有點(diǎn)難看抱歉,工具licecap)
實(shí)現(xiàn)思路
HTML結(jié)構(gòu)
<ul> <li> <div class="bg"> <p>JS</p> </div> </li> ..... </ul>
li作為鼠標(biāo)移入(mouseenter
)和鼠標(biāo)移出(mouseleave
)的載體。
div作為動(dòng)畫執(zhí)行的載體。
CSS
div采用absolute
定位,通過top、left改變它的位置。
由于div的top、left可能會(huì)超出li的大小,所以要設(shè)置li的overflow:hidden;
JS
1、采用JS操縱CSS3 transition動(dòng)畫
2、如何判斷鼠標(biāo)移入移除的方向
鼠標(biāo)坐標(biāo)的相關(guān)知識(shí)
MouseEvent對(duì)象
下面介紹幾個(gè)MouseEvent
中坐標(biāo)的相關(guān)知識(shí):
(clientX, clientY):
以可視區(qū)域?yàn)閰⒖枷档淖鴺?biāo)。
(pageX, pageY):
以整個(gè)頁面(包括滾動(dòng)條卷出的區(qū)域)為參考系的坐標(biāo)。
(screenX, screenY):
以你的電腦屏幕為參考系的坐標(biāo)。
獲取某個(gè)元素內(nèi)部的坐標(biāo)
function pointTo(element, e) { var elementBox = element.getBoundingClientRect(); return { x: e.clientX - elementBox.left, y: e.clientY - elementBox.top }; }
計(jì)算元素左上角的坐標(biāo)
function startPoint(element){ var x = 0,y = 0; while(element != null) { x += element.offsetLeft; y += element.offsetTop; element = element.offsetParent; } return { x: x, y: y } }
獲取元素的寬度和高度(不要認(rèn)為是width和height 新手特別容易犯錯(cuò))
offsetHeight與offsetWidth
簡單的封裝一下CSS3 transition動(dòng)畫
/* options參數(shù): obj: 運(yùn)動(dòng)的對(duì)象 speed: 運(yùn)動(dòng)的持續(xù)時(shí)間(可選) changeStyle: 改變的屬性,這里可能多個(gè),所以采用函數(shù)的方式(可選) callback: 回調(diào)函數(shù)(可選) */ function animation(options){ if(!options.obj) { return false; } //設(shè)置默認(rèn)持續(xù)時(shí)間 options.speed = options.speed || '.5s'; options.obj.style.transition = "all " + options.speed + " ease-in-out"; options.changeStyle.call(options.obj); var flag = false; options.obj.addEventListener('transitionend',function(){ //這里主要由于transitionend在每個(gè)屬性的動(dòng)畫執(zhí)行完多會(huì)走一遍,所以我們要讓它只執(zhí)行一次。 if(!flag) { options.callback && options.callback(); } },false); }
如何確定方向
這里要用到數(shù)學(xué)中的正切相關(guān)的概念,我自己畫了一張圖,不知道你們能不能看特明白:(奇丑。。。)
得到元素的運(yùn)動(dòng)方向
function getDirection(element,startPoint,pagePoint){ var halfWidth = element.offsetWidth / 2,halfHeight = element.offsetHeight / 2; //得到中心點(diǎn) var center = { x: startPoint.x + halfWidth, y: startPoint.y + halfHeight } //得到鼠標(biāo)偏離中心點(diǎn)的距離 var disX = pagePoint.x - center.x; var disY = pagePoint.y - center.y; if(disY < 0 && Math.abs(disY / disX) >= 1) { //上方 return 1; } else if(disY > 0 && Math.abs(disY / disX) >= 1) { //下 return 2; } else if(disX < 0 && Math.abs(disY / disX) < 1) { //左 return 3; } else { //右 return 4; } }
啟動(dòng)事件的代碼,有注釋
/* options中的參數(shù): 觸發(fā)事件的載體: targetElement 執(zhí)行動(dòng)畫的載體: animationElement */ function HoverAction(options) { if(!options.targetElement || !options.animationElement) { return false; } this.targetElement = options.targetElement; this.animationElement = options.animationElement; this.timeId = null; this.speed = "0.3s"; } HoverAction.prototype.addEvent = function() { //保存this的指向 var _this = this; _this.targetElement.addEventListener('mouseenter',function(e){ //得到鼠標(biāo)的坐標(biāo) var point = { x: e.pageX, y: e.pageY } console.log(point); //獲得方向 var dir = getDirection(_this.targetElement,startPoint(_this.targetElement),point); clearTimeout(_this.timeId); //取消過渡動(dòng)畫(防止重置動(dòng)畫載體位置時(shí)觸發(fā)過渡效果) _this.animationElement.style.transition = ""; //得到運(yùn)動(dòng)的方向,要確定動(dòng)畫載體的開始位置 switch(dir){ case 1: _this.animationElement.style.top = "-100%"; _this.animationElement.style.left = "0"; break; case 2: _this.animationElement.style.top = "100%"; _this.animationElement.style.left = "0"; break; case 3: _this.animationElement.style.top = "0"; _this.animationElement.style.left = "-100%"; break; case 4: _this.animationElement.style.top = "0"; _this.animationElement.style.left = "100%"; break; } //異步執(zhí)行 _this.timeId = setTimeout(function(){ animation({ obj: _this.animationElement, speed: _this.speed, changeStyle: function(){ this.style.top = "0"; this.style.left = "0"; } }); },20); },false); _this.targetElement.addEventListener('mouseleave',function(e){ var left,top; var point = { x: e.pageX, y: e.pageY } clearTimeout(_this.timeId); _this.animationElement.style.transition = ""; var dir = getDirection(_this.targetElement,startPoint(_this.targetElement),point); switch(dir) { case 1: top = '-100%'; left = '0'; break; case 2: top = '100%'; left = "0"; break; case 3: left = "-100%"; top = "0"; break; case 4: left = "100%"; top = "0"; break; } _this.timeId = setTimeout(function(){ animation({ obj: _this.animationElement, speed: _this.speed, changeStyle: function(){ this.style.top = top; this.style.left = left; } }); },20); },false); }
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能有所幫助,如果有疑問大家可以留言交流。
相關(guān)文章
12個(gè)提高JavaScript技能的概念(小結(jié))
這篇文章主要介紹了12個(gè)提高JavaScript技能的概念(小結(jié)),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-05-05javascript實(shí)現(xiàn)簡易計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)簡易計(jì)算器功能,實(shí)現(xiàn)四則運(yùn)算,小數(shù)點(diǎn),回退,歸0等功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09JavaScript 中Date對(duì)象的格式化代碼方法匯總
JavaScript默認(rèn)的時(shí)間格式我們一般情況下不會(huì)用,所以需要進(jìn)行格式化,下面小編給大家?guī)砹巳Njs date對(duì)象格式化實(shí)例代碼,需要的朋友參考下吧2017-09-09