1更灵活的函数.png
之前写过动画函数
ani(box,"width",500,1000,function(a){})
//box的width增加(减少)到500,总用时1s,
//完成动画之后的回调为function(a){},运算的结果a传递到回调函数中。
但是这样的封装比较局限,只能是改变元素的style,而封装成increase这个样的函数,应用场景会多一点。
increase(200,500,1000,function(a){
box.style.width=a+"px";
})
increase(0,1,1000,function(a){
box.style.opacity=a;//不用单位
})
//这样也可以完成动画,而且更加灵活
1increase.png
可以将计时器返回出来,在计时器还没有结束之前提前清除计时器clearIntarval(t);
小练习:
五个按钮,点击之后变色,hover之后变色
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div class="btn">
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
<button>5</button>
</div>
</body>
<script>
var buttons=document.getElementsByTagName("button");
var cur=0;
buttons[0].style.backgroundColor="orange";
for(var i=0;i<buttons.length;i++){
buttons[i].index=i;
buttons[i].onclick=function (){
buttons[cur].style.backgroundColor="white";
cur=this.index;
buttons[cur].style.backgroundColor="orange";
}
buttons[i].onmouseover=function(){
this.style.backgroundColor="orange";
}
buttons[i].onmouseout=function(){
//重要是这句
//点击按钮之后再mouseout就不能让他变白
if(this.index!=cur){
this.style.backgroundColor="white";
}
}
}
</script>
</html>
楼层滚动:
注意,浏览器刷新时,滚动条是不会重置的,但是代码会重新执行,假如说用户滚动到第三层时刷新了,刷新后楼层还是在第三层,所以刷新后应该让代码先在网页加载时执行一遍,所以把监听的函数提取出来,先执行一遍。而且我们之前写的是距离浏览器窗口顶部100px以内才执行相关操作,而用户是停留在第三层并不满足这个条件。所以判断当前可视区域是哪一个楼层还需要将判别条件重新定义。
判断当前楼层时,最好用区间表示,如果判断它具体到了哪个值,有可能会捕捉不到。遍历每一个楼层看是否有符合条件的。
第一层要自己设置nav[0].style.color="",不然打开页面,网页不滚动也是监听不到第一层的位置情况。
在同一楼层内滚动代码会执行多次,修改后的代码:
楼层滚动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
body{
background-color: black;
}
#content div{
opacity: .5;
height: 800px;
background-color: red;
font-size: 100px;
line-height: 800px;
text-align: center;
}
#nav{
position:fixed;
left: 50px;
top: 200px;
width: 50px;
text-align: center;
}
#nav li{
background-color: purple;
height: 30px;
line-height: 30px;
color: white;
list-style: none;
margin-top: 10px;
}
</style>
</head>
<body>
<div id="content">
<div>1</div>
<div style="background:blue">2</div>
<div style="background:orange">3</div>
<div style="background:pink">4</div>
</div>
<ul id="nav">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</body>
<script>
var contents=content.children;
var navs=nav.children;
var x=0;
var H=window.innerHeight||document.documentElement.clientHeight;
H/=2;
navs[x].style.background="green";
for(var i=0;i<navs.length;i++){
navs[i].index=i;
navs[i].onclick=function(){
var cur_st=document.body.scrollTop||document.documentElement.scrollTop;
increase(cur_st,contents[this.index].offsetTop,200,function(s){
// 直接获取offsettop是有可能不准的,用之前封装的那个方法就行
console.log("s",s)
document.body.scrollTop=s;
document.documentElement.scrollTop=s;
})
// 这样你改变offsettop时,就会触发window的onscroll事件
// 楼层导航按钮也会跟着变化
}
}
function scrollHandle(){
var st=document.body.scrollTop||document.documentElement.scrollTop;
for(var i=0;i<contents.length;i++){
var ot=contents[i].offsetTop;
// 这里的800是元素的高度,这个应该要获取,不能直接写死
if(ot<=st+H&&ot+800>st+H&&x!=i){
//ot<st+H当前楼层的顶部向上越过了屏幕的中线
//ot+800>st+H当前楼层的底部向下越过了屏幕的中线
navs[x].style.background="purple";
x=i;
navs[x].style.background="green";
console.log(x);
}
}
}
scrollHandle();
//是为了解决滚动后刷新获取不到当前楼层的问题
window.onscroll=scrollHandle;
function increase(start,end,t,fun){
var x=end-start;
var step;
step=x/t*16.7
var timer=setInterval(function(){
start+=step;
if(Math.abs(start-end)<=Math.abs(step)){
// 差值小于step就清除计时器
start=end;
clearInterval(timer)
}
fun(start);
},16.7)
}
</script>
</html>
这里用的是window.onscroll是一级dom事件,一级dom事件会有别覆盖的风险,一个页面有多个window.onscroll事件时就麻烦了(window是公共的,谁都可以给他绑定事件),所以以后开发项目尽量用事件监听。
事件监听封装
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="box">按钮</button>
</body>
<script>
function addEvent(el,type,fn){
if(el.addEventListener){
el.addEventListener(type,fn)
// 这里面也是有事件对象的
}else{
// 在IE当中this不是指向el,所以用call
el.attachEvent("on"+type,function(e){
// 这个e是事件对象
fn.call(this,e)
// 将事件对象传到fn内面
})
}
}
addEvent(box,"click",function(e){
e=e||window.event;
console.log(e.target||e.srcElement);
})
</script>
</html>
可以将这些处理兼容或是像之前的ani、添加删除类名的这些封装好的函数都放在一个js文件中,到时候项目中需要就直接应用,就不用再处理这些底层的东西了。