共计 4420 个字符,预计需要花费 12 分钟才能阅读完成。
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;
}
问题
浏览器打开后,特效有时从上边出来,有时从下边出来,不知道为啥
正文完