css和html代码
<!doctype html><html lang="en"> <head> <meta charset="UTF-8"> <meta name="Keywords" content=""> <meta name="Description" content=""> <title>document</title> <style type="text/css"> *{ padding:0; margin:0 } img{ vertical-align:middle; } #box{ width:1250px; height:360px; margin:100px auto; font-family:'Microsoft yahei'; } #box ul li{ list-style:none; float:left; margin:0 10px; position:relative; overflow:hidden; } #box ul li a{ width:230px; height:360px; position:absolute; left: 0; top: 360px; background:url("images/new-bg.png"); text-decoration:none; } #box ul li a p{ color:#fff; font-size:14px; text-align:center; } #box ul li a p.p1{ padding-top:160px; } </style> </head> <body> <div id='box'> <ul id="list"> <li> <img src='images/1.jpg'/> <a href='#'> <p class='p1'>秋冬上新 领券立减20</p> <p>点击进入</p> </a> </li> <li> <img src='images/2.jpg'/> <a href='#'> <p class='p1'>钜惠满138减15</p> <p>点击进入</p> </a> </li> <li> <img src='images/3.jpg'/> <a href='#'> <p class='p1'>冬装尖品 强势登陆</p> <p>点击进入</p> </a> </li> <li> <img src='images/4.jpg'/> <a href='#'> <p class='p1'>十一国庆除出游季</p> <p>购新衣才够【型】</p> </a> </li> <li> <img src='images/5.jpg'/> <a href='#'> <p class='p1'>秋上新</p> <p>点击进入</p> </a> </li> </ul> </div></html>
js实现思路
- 什么是js语言?js语言是基于原型的动态解释性语言,其基本操作分为css样式操作和dom节点操作。基于原型:存在对象、声明,就有原型。动态解释性:语言可以在任何环境下运行,没有限制。js不仅仅能够用于特效,插件框架开发、机器学习、数据分析、人工智能,都可以通过js实现
- 实现简单的鼠标划入操作思路:
(1)获取dom元素
(2)考虑两个事件:mouseenter、mouseleave,注册事件实现移入移出操作。
元素获取
- 获取元素有三种方法:原生js方法(get方法)、$方法、query方法。其中get方法由js原生提供,获取速度最优,$和query方法都是由get系列封装而成。不同在于$是jQuery提供,性能最差;query由html5提供,而且经过了优化,获取速度仅次于get原生方法。
- 在这里我们使用原生js方法实现:
<script> var oBox=document.getElementById('box'); var aLi=oBox.getElementsByTagName('li'); </script>
使用for循环进行事件注册
- for循环可以给每个li绑定一个事件,从而实现了事件注册
//使用for循环进行事件注册 for(var i=0,aLiLen=aLi.length;i<aLiLen;i++){ //这样较for(var i=0;i<aLi.length;i++)性能更优,因为不必每次计算aLi.length aLi[i].onmouseenter=function(){ console.log(1); } }
- 首先注意的是,由于box有多个li子元素,所以aLi是一个伪数组。即具有数组的属性(下标、长度),而没有数组的方法(foreach、push、sort)。其次注意,enter、leave、over、out的区别:enter、leave在不冒泡条件下进行,由外到里;out、over在冒泡条件下进行,由里到外。冒泡:事件的执行顺序由子集向父集发出,即由里到外。
- 但是,一般情况下,我们不采用for循环进行事件注册。原因:
(1)当事件绑定特别多时,容易造成事件覆盖。即只执行后边的事件,前边事件不执行
(2)性能特别差,进行循环遍历为每个li绑定事件;但是鼠标不进入的话,就不会触发事件。这样会造成浏览器加载资源的浪费(当一万个事件时...)
因此,我们通常采用事件代理(事件委托)实现事件注册。事件代理基于事件监听实现,不必给每个li进行绑定
基于事件监听的事件代理
- 在实现特效时,首先要学会观察,不要着急一上来就干。思考此特效的实现过程:鼠标移入-》获取鼠标坐标-》获取元素宽高,进而得到元素距离浏览器各边的大小-》计算鼠标坐标和四条边的距离-》哪边的绝对值最小,就说明从哪边移入(移入瞬间,差值接近0)
- 若有两个的绝对值是相等的,我们执行哪个事件呢?当然是后边的,因为事件覆盖嘛。
- 在计算得到四个绝对值中的最小值后,我们加以val的判断,就能得到鼠标是从哪个方向移入或者移出了。但是后边的动画怎么实现呢?我们分两步完成,假设鼠标从上边移入,我们先瞬间令背景图移动到最上边,然后缓慢的移下来。这个动画的实现过程我们使用链式操作实现。链式操作的原理很简单,就是每次方法执行完后返回this对象,这样后面的方法就可以继续在this环境下执行。
//获取元素 var oBox=document.getElementById('box'); var aLi=oBox.getElementsByTagName('li'); // //使用for循环进行事件注册 // for(var i=0,aLiLen=aLi.length;i<aLiLen;i++){ // //这样较for(var i=0;i<aLi.length;i++)性能更优,因为不必每次计算aLi.length // aLi[i].onmouseenter=function(){ // console.log(1); // } // } //基于事件监听的事件代理 oBox.addEventListener('mouseenter',function(e){ //检验和调试 //最后的false\true参数表示是否冒泡。默认为false,表示冒泡阶段 //console.log(1);//参数为true一次打印多个1;false一次打印一个1 //console.log(e);//true一次会触发多个事件,是我们想要的 //console.log(e.target.tagName);//确认真的没错 //代码优化 var target=e.target; if(target.tagName.toLowerCase()=='li'){ //得到鼠标移入li瞬间的鼠标坐标 var x=e.clientX; var y=e.clientY; //得到li四条边距离浏览器左部和顶部的距离 var oT=target.offsetTop; var oB=oT+target.offsetHeight; var oL=target.offsetLeft; var oR=oL+target.offsetWidth; //计算鼠标坐标和四条边的距离,取绝对值 var diffT=Math.abs(y-oT); var diffB=Math.abs(y-oB); var diffL=Math.abs(x-oL); var diffR=Math.abs(x-oR); //取最小值为方向 var direction=Math.min(diffT,diffB,diffL,diffR); //判断是鼠标移入还是移出 var val=e.type.toLowerCase(); //console.log(diffT,diffB,diffL,diffR);//检验一下 //switch语句选择方向 switch(direction){ //方法是一样的,只是方向不一样。我们只要封装函数即可 case diffT: moveTo('top',val,target); //console.log('从上移入'); break; case diffB: moveTo('bottom',val,target); //console.log('从下移入'); break; case diffL: moveTo('left',val,target); //console.log('从左移入'); break; case diffR: moveTo('right',val,target); //console.log('从右移入'); break; } } },true); function moveTo(aspect,mouse,aim){ //aspect表示鼠标移入方向; // mouse表示鼠标 // aim表示操作的对象 // from瞬间移动的距离 // to后来的距离,默认为0 if(mouse=='mouseenter'){ aim.children[1].css(aspect).enter(aspect); }else{ } } Node.prototype.css=function(aspect){ if(aspect=='top'){ this.style[aspect]=-360+'px'; this.style.left=0; } return this; } Node.prototype.enter=function(aspect){ setTimeout(function(){ this.style[aspect]=0+'px'; this.style.transition='.3s'; }.bind(this),0) //this在此处默认指向windows(因为settimeout是windows调用的函数),我们使用bind强制事件绑定,使其指向当前对象 // this.style[aspect]=to+'px'; // this.style.transition='.3s'; //若不使用setTimeOut伪异步操作的话,会发生事件覆盖,即前边的css被后边的enter覆盖 return this; }
问题
浏览器打开后,特效有时从上边出来,有时从下边出来,不知道为啥