楼层滚动

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文件中,到时候项目中需要就直接应用,就不用再处理这些底层的东西了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容