JavaScript进阶--拉勾网鼠标移入移出效果
Lorene8383
8年前
<h3><strong>JavaScript进阶</strong></h3> <p>1024丝毫不减少我敲写代码的激情,因为我闻到了代码的味道。</p> <p><strong>先上效果图(gif自己录制的,有点难看抱歉,工具licecap)</strong></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/1881c88969ea64b359fb074a8d55d52a.gif"></p> <p>其实也是个偶然的机会,让我想去研究一下这个效果。主要是由于有个群里的人发了个讲解这个效果的链接,当时也没怎么在意,然后过两天,突然就想起这件事,便去拉勾网一看,哎呦效果不错,就想去找找那个链接看一下。没想到找了半天没找到了,没办法只能自己研究了。(自己独立思考的意识还是不够啊,惭愧!)</p> <p><strong>思路</strong></p> <div contenteditable="false" tabindex="-1"> <pre data-widget="codeSnippet"> <code class="language-javascript hljs">------------ HTML结构 ------------ <ul> <li> <div class="bg"> <p>JS</p> </div> </li> ..... </ul> li作为鼠标移入(mouseenter)和鼠标移出(mouseleave)的载体。 div作为动画执行的载体。 ------------ CSS ------------ div采用absolute定位,通过top、left改变它的位置。 由于div的top、left可能会超出li的大小,所以要设置li的overflow:hidden; ----------- JS ----------- 1、采用JS操纵CSS3 transition动画 2、如何判断鼠标移入移除的方向</code></pre> <img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw=="> <span style="background:url(http://www.open-open.com/lib/ckeditor/plugins/widget/images/handle.png) rgba(220, 220, 220, 0.498039); display:block; left:0px; top:-15px"><img height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15"></span> </div> <p><strong>鼠标坐标的相关知识</strong></p> <div contenteditable="false" tabindex="-1"> <pre data-widget="codeSnippet"> <code class="language-javascript hljs">------------------ MouseEvent对象 ------------------ 下面介绍几个MouseEvent中坐标的相关知识: (clientX, clientY): 以可视区域为参考系的坐标。 (pageX, pageY): 以整个页面(包括滚动条卷出的区域)为参考系的坐标。 (screenX, screenY): 以你的电脑屏幕为参考系的坐标。 获取某个元素内部的坐标 <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">pointTo</span><span class="hljs-params">(element, e)</span> {</span> <span class="hljs-keyword">var</span> elementBox = element.getBoundingClientRect(); <span class="hljs-keyword">return</span> { x: e.clientX - elementBox.left, y: e.clientY - elementBox.top }; } 计算元素左上角的坐标 <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">startPoint</span><span class="hljs-params">(element)</span>{</span> <span class="hljs-keyword">var</span> x = <span class="hljs-number">0</span>,y = <span class="hljs-number">0</span>; <span class="hljs-keyword">while</span>(element != <span class="hljs-literal">null</span>) { x += element.offsetLeft; y += element.offsetTop; element = element.offsetParent; } <span class="hljs-keyword">return</span> { x: x, y: y } } 获取元素的宽度和高度(不要认为是width和height 新手特别容易犯错) offsetHeight与offsetWidth</code></pre> <img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw=="> <span style="background:url(http://www.open-open.com/lib/ckeditor/plugins/widget/images/handle.png) rgba(220, 220, 220, 0.498039); display:block; left:0px; top:-15px"><img height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15"></span> </div> <p><strong>简单的封装一下CSS3 transition动画</strong></p> <div contenteditable="false" tabindex="-1"> <pre data-widget="codeSnippet"> <code class="language-javascript hljs"><span class="hljs-comment">/* options参数: obj: 运动的对象 speed: 运动的持续时间(可选) changeStyle: 改变的属性,这里可能多个,所以采用函数的方式(可选) callback: 回调函数(可选) */</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">animation</span><span class="hljs-params">(options)</span>{</span> <span class="hljs-keyword">if</span>(!options.obj) { <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; } <span class="hljs-comment">//设置默认持续时间</span> options.speed = options.speed || <span class="hljs-string">'.5s'</span>; options.obj.style.transition = <span class="hljs-string">"all "</span> + options.speed + <span class="hljs-string">" ease-in-out"</span>; options.changeStyle.call(options.obj); <span class="hljs-keyword">var</span> flag = <span class="hljs-literal">false</span>; options.obj.addEventListener(<span class="hljs-string">'transitionend'</span>,<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span>{</span> <span class="hljs-comment">//这里主要由于transitionend在每个属性的动画执行完多会走一遍,所以我们要让它只执行一次。</span> <span class="hljs-keyword">if</span>(!flag) { options.callback && options.callback(); } },<span class="hljs-literal">false</span>); }</code></pre> <img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw=="> <span style="background:url(http://www.open-open.com/lib/ckeditor/plugins/widget/images/handle.png) rgba(220, 220, 220, 0.498039); display:block; left:0px; top:-15px"><img height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15"></span> </div> <p><strong>如何确定方向</strong></p> <p>这里要用到数学中的正切相关的概念,我自己画了一张图,不知道你们能不能看特明白:(奇丑。。。)</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/c0b7484a5ef7c46c114d535374fa4856.jpg"></p> <div contenteditable="false" tabindex="-1"> <pre data-widget="codeSnippet"> <code class="language-javascript hljs">-------------------- 得到元素的运动方向 -------------------- <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getDirection</span><span class="hljs-params">(element,startPoint,pagePoint)</span>{</span> <span class="hljs-keyword">var</span> halfWidth = element.offsetWidth / <span class="hljs-number">2</span>,halfHeight = element.offsetHeight / <span class="hljs-number">2</span>; <span class="hljs-comment">//得到中心点</span> <span class="hljs-keyword">var</span> center = { x: startPoint.x + halfWidth, y: startPoint.y + halfHeight } <span class="hljs-comment">//得到鼠标偏离中心点的距离</span> <span class="hljs-keyword">var</span> disX = pagePoint.x - center.x; <span class="hljs-keyword">var</span> disY = pagePoint.y - center.y; <span class="hljs-keyword">if</span>(disY < <span class="hljs-number">0</span> && <span class="hljs-built_in">Math</span>.abs(disY / disX) >= <span class="hljs-number">1</span>) { <span class="hljs-comment">//上方</span> <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>; } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(disY > <span class="hljs-number">0</span> && <span class="hljs-built_in">Math</span>.abs(disY / disX) >= <span class="hljs-number">1</span>) { <span class="hljs-comment">//下</span> <span class="hljs-keyword">return</span> <span class="hljs-number">2</span>; } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(disX < <span class="hljs-number">0</span> && <span class="hljs-built_in">Math</span>.abs(disY / disX) < <span class="hljs-number">1</span>) { <span class="hljs-comment">//左</span> <span class="hljs-keyword">return</span> <span class="hljs-number">3</span>; } <span class="hljs-keyword">else</span> { <span class="hljs-comment">//右</span> <span class="hljs-keyword">return</span> <span class="hljs-number">4</span>; } }</code></pre> <img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw=="> <span style="background:url(http://www.open-open.com/lib/ckeditor/plugins/widget/images/handle.png) rgba(220, 220, 220, 0.498039); display:block; left:0px; top:-15px"><img height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15"></span> </div> <p><strong>启动事件的代码,有注释</strong></p> <div contenteditable="false" tabindex="-1"> <pre data-widget="codeSnippet"> <code class="language-javascript hljs"><span class="hljs-comment">/* options中的参数: 触发事件的载体: targetElement 执行动画的载体: animationElement */</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HoverAction</span><span class="hljs-params">(options)</span> {</span> <span class="hljs-keyword">if</span>(!options.targetElement || !options.animationElement) { <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; } <span class="hljs-keyword">this</span>.targetElement = options.targetElement; <span class="hljs-keyword">this</span>.animationElement = options.animationElement; <span class="hljs-keyword">this</span>.timeId = <span class="hljs-literal">null</span>; <span class="hljs-keyword">this</span>.speed = <span class="hljs-string">"0.3s"</span>; } HoverAction.prototype.addEvent = <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span> {</span> <span class="hljs-comment">//保存this的指向</span> <span class="hljs-keyword">var</span> _this = <span class="hljs-keyword">this</span>; _this.targetElement.addEventListener(<span class="hljs-string">'mouseenter'</span>,<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(e)</span>{</span> <span class="hljs-comment">//得到鼠标的坐标</span> <span class="hljs-keyword">var</span> point = { x: e.pageX, y: e.pageY } console.log(point); <span class="hljs-comment">//获得方向</span> <span class="hljs-keyword">var</span> dir = getDirection(_this.targetElement,startPoint(_this.targetElement),point); clearTimeout(_this.timeId); <span class="hljs-comment">//取消过渡动画(防止重置动画载体位置时触发过渡效果)</span> _this.animationElement.style.transition = <span class="hljs-string">""</span>; <span class="hljs-comment">//得到运动的方向,要确定动画载体的开始位置</span> <span class="hljs-keyword">switch</span>(dir){ <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>: _this.animationElement.style.top = <span class="hljs-string">"-100%"</span>; _this.animationElement.style.left = <span class="hljs-string">"0"</span>; <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> <span class="hljs-number">2</span>: _this.animationElement.style.top = <span class="hljs-string">"100%"</span>; _this.animationElement.style.left = <span class="hljs-string">"0"</span>; <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> <span class="hljs-number">3</span>: _this.animationElement.style.top = <span class="hljs-string">"0"</span>; _this.animationElement.style.left = <span class="hljs-string">"-100%"</span>; <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> <span class="hljs-number">4</span>: _this.animationElement.style.top = <span class="hljs-string">"0"</span>; _this.animationElement.style.left = <span class="hljs-string">"100%"</span>; <span class="hljs-keyword">break</span>; } <span class="hljs-comment">//异步执行</span> _this.timeId = setTimeout(<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span>{</span> animation({ obj: _this.animationElement, speed: _this.speed, changeStyle: <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span>{</span> <span class="hljs-keyword">this</span>.style.top = <span class="hljs-string">"0"</span>; <span class="hljs-keyword">this</span>.style.left = <span class="hljs-string">"0"</span>; } }); },<span class="hljs-number">20</span>); },<span class="hljs-literal">false</span>); _this.targetElement.addEventListener(<span class="hljs-string">'mouseleave'</span>,<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(e)</span>{</span> <span class="hljs-keyword">var</span> left,top; <span class="hljs-keyword">var</span> point = { x: e.pageX, y: e.pageY } clearTimeout(_this.timeId); _this.animationElement.style.transition = <span class="hljs-string">""</span>; <span class="hljs-keyword">var</span> dir = getDirection(_this.targetElement,startPoint(_this.targetElement),point); <span class="hljs-keyword">switch</span>(dir) { <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>: top = <span class="hljs-string">'-100%'</span>; left = <span class="hljs-string">'0'</span>; <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> <span class="hljs-number">2</span>: top = <span class="hljs-string">'100%'</span>; left = <span class="hljs-string">"0"</span>; <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> <span class="hljs-number">3</span>: left = <span class="hljs-string">"-100%"</span>; top = <span class="hljs-string">"0"</span>; <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> <span class="hljs-number">4</span>: left = <span class="hljs-string">"100%"</span>; top = <span class="hljs-string">"0"</span>; <span class="hljs-keyword">break</span>; } _this.timeId = setTimeout(<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span>{</span> animation({ obj: _this.animationElement, speed: _this.speed, changeStyle: <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span>{</span> <span class="hljs-keyword">this</span>.style.top = top; <span class="hljs-keyword">this</span>.style.left = left; } }); },<span class="hljs-number">20</span>); },<span class="hljs-literal">false</span>); }</code></pre> <img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw=="> <span style="background:url(http://www.open-open.com/lib/ckeditor/plugins/widget/images/handle.png) rgba(220, 220, 220, 0.498039); display:block; left:0px; top:-15px"><img height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15"></span> </div> <p> </p> <p> </p> <p>来自:https://github.com/15751165579/ThinkInCoding/blob/master/文章/JavaScript进阶--拉勾网鼠标移入移出效果.md</p> <p> </p>