PC端网页特效二

2. 元素可视区client系列

client翻译过来都是客户端,我们使用client系列的相关属性来获取元素可视区的相关信息,通过client系列的相关属性可以动态的得到该元素的边框大小、元素大小等

client系列属性作用
element.clientTop返回元素上边框的大小
element.clientLeft返回元素左边框的大小
element.clientWidth返回自身包括padding、内容区的宽度,不含边框,返回数值不带单位
element.clientHeight返回自身包括padding、内容去的高度,不含边框,返回数值不带单位

                                

 

案例:淘宝flexible.js源码分析

1.立即执行函数 (function(){} )()

不需要调用,立马能够自己执行的函数

1.(function [函数名]() {})()
2.(function [函数名](){}());

注意:如果有多个立即执行函数,要用;隔开 

主要作用:创建一个独立的作用域 ,里面所有的变量都是局部变量,不会有命名冲突的情况

(function flexible(window, document) {
    // 获取的html 的根元素
    var docEl = document.documentElement
        // dpr 物理像素比 pc端dpr=1 移动端dpr=2
    var dpr = window.devicePixelRatio || 1

    // adjust body font size  设置我们body 的字体大小
    function setBodyFontSize() {
        // 如果页面中有body 这个元素 就设置body的字体大小
        if (document.body) {
            document.body.style.fontSize = (12 * dpr) + 'px'
        } else {
            // 如果页面中没有body 这个元素,则等着 我们页面主要的DOM元素加载完毕再去设置body
            // 的字体大小
            document.addEventListener('DOMContentLoaded', setBodyFontSize)
        }
    }
    setBodyFontSize();

    // set 1rem = viewWidth / 10    设置我们html 元素的文字大小
    function setRemUnit() {
        var rem = docEl.clientWidth / 10
        docEl.style.fontSize = rem + 'px'
    }

    setRemUnit()

    // reset rem unit on page resize  当我们页面尺寸大小发生变化的时候,要重新设置下rem 的大小
    window.addEventListener('resize', setRemUnit)
        // pageshow 是我们重新加载页面触发的事件
    window.addEventListener('pageshow', function(e) {
        // e.persisted 返回的是true 就是说如果这个页面是从缓存取过来的页面,也需要从新计算一下rem 的大小
        if (e.persisted) {
            setRemUnit()
        }
    })

    // detect 0.5px supports  有些移动端的浏览器不支持0.5像素的写法
    if (dpr >= 2) {
        var fakeBody = document.createElement('body')
        var testElement = document.createElement('div')
        testElement.style.border = '.5px solid transparent'
        fakeBody.appendChild(testElement)
        docEl.appendChild(fakeBody)
        if (testElement.offsetHeight === 1) {
            docEl.classList.add('hairlines')
        }
        docEl.removeChild(fakeBody)
    }
}(window, document))

 整个js文件都包含在一个立即执行函数里面,只要引用了这个文件,就直接执行,不需要调用,而且再引用其他的js文件,不会发生命名冲突的情况

2.pageshow事件

pageshow是重新加载页面触发的事件

下面三种情况都会刷新页面,都会触发load事件

  1. a标签的超链接
  2. F5或者刷新按钮(强制刷新)
  3. 前进后退按钮

但是在火狐浏览器中,有一个特点叫做”往返缓存“,这个缓存中不仅保存着页面数据,还保存了DOM和 JavaScript的状态,实际上是将整个页面都保存在了内存里,所以此时后退按钮不会刷新页面。

此时可以使用pageshow事件来触发,这个事件在页面显示时触发,无论页面是否来自缓存,在重新加载页面中,pageshow会在load事件触发后触发,根据事件对象中的persisted来判断是否是缓存中的页面触发的pageshow事件,注意这个事件给window添加

3. 元素滚动scroll系列

3.1 元素scroll系列属性

scroll翻译过来就是滚动的,我们使用scroll系列的相关属性可以动态的得到该元素的大小、滚动距离等

scroll系列属性作用
element.scrollTop返回被卷去的上侧距离,返回数值不带单位
element.scrollLeft返回被卷去的左侧距离,返回数值不带  单位
element.scrollWidth返回自身实际的宽度,不含边框,返回数值不带单位
element.scrollHeight返回自身实际的高度,不含边框,返回数值不带单位
<style>
        div {
            width: 200px;
            height: 200px;
            background-color: pink;
            border: 10px solid red;
            padding: 5px;

        }
    </style>

<body>
    <div>
        我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容
    </div>
    <script>
        // scroll 系列
        var div = document.querySelector('div');
        // scrollHeight是真正内容的大小
        console.log(div.scrollHeight);
        console.log(div.clientHeight);
    </script>
</body>

                                                        

                                               

3.2 页面被卷去的头部

如果浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条,当滚动条向下滚动时,页面上面被隐藏掉的高度,我们就称为页面被卷去的头部,滚动条在滚动时会触发onscroll事件

<style>
        div {
            width: 200px;
            height: 200px;
            background-color: pink;
            border: 10px solid red;
            padding: 10px;
            overflow: auto;
        }
    </style>

<body>
    <div>
        我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容
        我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容
    </div>
    <script>
        // scroll 系列
        var div = document.querySelector('div');
        console.log(div.scrollHeight);
        console.log(div.clientHeight);
        // scroll滚动事件当我们滚动条发生变化会触发的事件
        div.addEventListener('scroll', function () {
            console.log(div.scrollTop);

        })
    </script>
</body>

 

案例:仿淘宝固定右侧侧边栏

  1.  需要用到页面滚动事件scroll,因为是页面滚动,所以事件源是document
  2. 滚动到某个位置,就是判断页面被卷去的上部值
  3. 页面被卷去的头部:可以通过window.pageYOffset获得,如果是被卷去的左侧 window.pageXOffset
  4. 注意:元素被卷去的头部是element.scrollTop,如果是页面被卷去的头部则是window.pageYOffset

注意:其实banner到页面最顶部的距离offsetTop,就是页面被卷上去的距离,不用写死,一定要在滚动事件外面定义,因为随着页面滚动这个值会发生改变

3.3 页面被卷去的头部兼容性解决方案

需要注意的是,页面被卷去的头部,有兼容性问题,因此被卷去的头部通常有如下几种写法:

  1. 声明了DTD(<!DOCTYPE html>),使用document.documentElement.scrollTop
  2. 未声明DTD,使用document.body.scrollTop
  3. 新方法window.pageYOffset和window.pageXOffset,IE9开始支持

 

三大系列总结

三大系列大小对比作用
element.offsetWidth返回自身包括padding、边框、内容区的宽度,返回数值不带单位
element.clientWidth返回自身包括padding、内容区的宽度,不含边框,返回数值不带单位
element.scrollWidth返回自身实际的宽度,不带边框,返回数值不带单位

                        

                         

                         

 它们主要用法:

  1. offset系列经常用于获得元素位置 offsetLeft offsetTop
  2. client经常用于获取元素大小 clientWidth clientHeight
  3. scroll经常用于获取滚动距离 scrollTop scrollLeft
  4. 注意页面滚动的距离通过window.pageXOffset获得

mouseenter和mouseover的区别

mouseenter鼠标事件

  • 当鼠标移动到元素上时就会触发mouseenter事件
  • 类似mouseover,它们两者之间的差别是
  • mouseover鼠标经过自身盒子会触发,经过子盒子还会触发。mouseenter只会经过自身盒子触发 
  • 之所以这样,就是因为mouseenter不会冒泡
  • 跟mouseenter搭配 鼠标离开mouseleave 同样不会冒泡

<style>
        .father {
            width: 300px;
            height: 300px;
            background-color: pink;
            margin: 100px auto;
        }

        .son {
            width: 200px;
            height: 200px;
            background-color: purple;
        }
    </style>

<body>
    <div class="father">
        <div class="son"></div>
    </div>
    <script>
        var father = document.querySelector('.father');
        var son = document.querySelector('.son');
        father.addEventListener('mouseover', function () {
            console.log('鼠标经过');
        })

    </script>
</body>

4. 动画函数封装

4.1 动画实现原理

核心原理:通过定时器setInterval()不断移动盒子位置

实现步骤:

  1. 获得盒子当前位置
  2. 让盒子在当前位置加上1个移动距离
  3. 利用定时器不断重复这个操作
  4. 加一个结束定时器的条件
  5. 注意此元素需要添加定位,才能使用element.style.left

注意:移动400px之后停止动画,本质是停止计时器

 

4.2 动画函数简单封装

注意函数需要传递2个参数,动画对象移动到的距离

 <style>
        div {
            position: absolute;
            left: 0;
            width: 100px;
            height: 100px;
            background-color: pink;
        }

        span {
            position: absolute;
            left: 0;
            top: 200px;
            display: block;
            width: 150px;
            height: 150px;
            background-color: purple;
        }
    </style>

<body>
    <div></div>
    <span>郭德纲</span>
    <script>
        // 简单动画函数封装 obj目标对象 target目标位置
        function animate(obj, target) {
            var timer = setInterval(function () {
                if (obj.offsetLeft >= target) {
                    clearInterval(timer);
                }
                obj.style.left = obj.offsetLeft + 5 + 'px';

            }, 30);
        }
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        animate(div, 300);
        animate(span, 200);
    </script>
</body>

 

4.3 动画函数给不同元素记录不同定时器

如果多个元素都使用这个动画函数,每次都要var声明定时器,而且每个函数调用时定时器都起了相同的名字,我们可以给不同的元素使用不同的定时器(自己专门用自己的定时器)

核心原理:利用js是一门动态语言,可以很方便的给当前对象添加属性

var obj = {};
obj.name = 'andy'; //通过属性名给对象添加属性

 

 优化

<body>
    <button>点击之后郭德纲才走</button>
    <div></div>
    <span>郭德纲</span>
    <script>
        // 简单动画函数封装 obj目标对象 target目标位置
        function animate(obj, target) {
            // 在执行定时器的最开始,把之前的定时器全都清除,保证每个元素只有一个定时器
            clearInterval(obj.timer)
            obj.timer = setInterval(function () {
                if (obj.offsetLeft >= target) {
                    clearInterval(obj.timer);
                }
                obj.style.left = obj.offsetLeft + 5 + 'px';

            }, 30);
        }
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        var btn = document.querySelector('button');
        btn.addEventListener('click', function () {
            animate(span, 200);

        });
        animate(div, 300);
    </script>
</body>

4.4 缓动效果原理

缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来

思路:

  1. 让盒子每次移动的距离 慢慢变小,速度就会慢慢降下来
  2. 核心算法:每次移动的距离(步长)=(目标值-现在的位置) / 10
  3. 停止的条件是:让当前盒子位置等于目标位置就停止定时器
  4. 注意步长值需要取整(向上取整),如果不取整,小数会让最后的效果和预想的不一样,比规定的要小
  5. 每次定时器都会重新计算一次移动的距离,所以计算步长的公式要写在定时器里面

目标距离是100 目前的位置0

第一次移动距离:(100-0)/10 = 10

第二次移动距离:(100-10)/10 = 9

第三次移动距离:(100-19)/10 = 8.1

......................

<style>
        div {
            position: absolute;
            left: 0;
            width: 100px;
            height: 100px;
            background-color: pink;
        }

        span {
            position: absolute;
            left: 0;
            top: 200px;
            display: block;
            width: 150px;
            height: 150px;
            background-color: purple;
        }
    </style>


<body>
    <button>点击夏雨荷才走</button>
    <span>夏雨荷</span>
    <script>
        // 缓动动画函数封装obj目标对象 target 目标位置
        // 思路:
        // 1. 让盒子每次移动的距离慢慢变小, 速度就会慢慢落下来。
        // 2. 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长
        // 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
        function animate(obj, target) {
            // 先清除以前的定时器,只保留当前的一个定时器执行
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {
                // 取整
                var step = Math.ceil((target - obj.offsetLeft) / 10);
                if (obj.offsetLeft == target) {
                    // 停止动画 本质是停止定时器
                    clearInterval(obj.timer);
                }

                obj.style.left = obj.offsetLeft + step + 'px';

            }, 15);
        }
        var span = document.querySelector('span');
        var btn = document.querySelector('button');

        btn.addEventListener('click', function () {
            // 调用函数
            animate(span, 500);
        })
        // 匀速动画 就是盒子是当前的位置+固定的值
        // 缓动动画 盒子当前的位置+变化的值(目标值-当前的位置)/10

    </script>
</body>

4.5 缓动动画在多个目标值之间移动

可以让动画函数从800移动到500

当我们点击按钮的时候,判断步长是正值还是负值

  1. 如果是正值,则步长往大了取整
  2. 如果是负值,则步长向小了取整
  • 如果是从小的目标值向大的目标值移动,那么计算步长值的时候要向上取整(天花板)
  • 如果是从大的目标值向小的目标值移动,那么计算步长值的时候要向下取整(地板)

<style>
        div {
            position: absolute;
            left: 0;
            width: 100px;
            height: 100px;
            background-color: pink;
        }

        span {
            position: absolute;
            left: 0;
            top: 200px;
            display: block;
            width: 150px;
            height: 150px;
            background-color: purple;
        }
    </style>

<body>
    <button class="btn500">点击夏雨荷移动到500</button>
    <button class="btn800">点击夏雨荷移动到800</button>
    <span>夏雨荷</span>
    <script>

        function animate(obj, target) {
            // 先清除以前的定时器,只保留当前的一个定时器执行
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {
                // 步长值写到定时器的里面
                // 把我们步长值改为整数 不要出现小数的问题
                var step = (target - obj.offsetLeft) / 10;
                step = step > 0 ? Math.ceil(step) : Math.floor(step);
                if (obj.offsetLeft == target) {
                    // 停止动画 本质是停止定时器
                    clearInterval(obj.timer);
                }
                // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
                obj.style.left = obj.offsetLeft + step + 'px';

            }, 15);
        }
        var span = document.querySelector('span');
        var btn500 = document.querySelector('.btn500');
        var btn800 = document.querySelector('.btn800');

        btn500.addEventListener('click', function () {
            // 调用函数
            animate(span, 500);
        })

        btn800.addEventListener('click', function () {
            animate(span, 800);
        })
            // 匀速动画 就是 盒子是当前的位置 +  固定的值 10
            // 缓动动画就是  盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10)
    </script>
</body>

 

4.6 动画函数添加回调函数

回调函数原理:函数可以作为一个参数。将这个函数作为参数传到另一个函数里面,当这个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调

比如上面的例子,如果想要紫色盒子移动完500px之后变成红色,就要执行完移动的函数之后再执行变成紫色的函数 

回调函数写的位置:定时器结束的位置  

如果有回调函数就执行 if判断一下

 

 盒子移动800px之后变成红色

4.7 动画函数封装到单独JS 文件里面

因为以后经常使用这个动画函数,可以单独封装到一个JS文件里面,使用的时候引用这个JS文件即可

 

animate.js

function animate(obj, target, callback) {

    clearInterval(obj.timer);
    obj.timer = setInterval(function () {
        var step = (target - obj.offsetLeft) / 10;
        step = step > 0 ? Math.ceil(step) : Math.floor(step);
        if (obj.offsetLeft == target) {
            // 停止动画 本质是停止定时器
            clearInterval(obj.timer);
            // 回调函数写到定时器结束里面
            callback();

        }

        obj.style.left = obj.offsetLeft + step + 'px';

    }, 15);
}

<!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>
        .sliderbar {
            position: fixed;
            right: 0;
            bottom: 100px;
            width: 40px;
            height: 40px;
            text-align: center;
            line-height: 40px;
            cursor: pointer;
            color: #fff;
        }

        .con {
            position: absolute;
            left: 0;
            top: 0;
            width: 200px;
            height: 40px;
            background-color: purple;
            z-index: -1;
        }
    </style>
    <script src="./JS/animate.js"></script>
</head>

<body>
    <div class="sliderbar">
        <span>←</span>
        <div class="con">问题反馈</div>
    </div>

    <script>
        var sliderbar = document.querySelector('.sliderbar');
        var con = document.querySelector('.con');

        // 当我们鼠标经过 sliderbar 就会让 con这个盒子滑动到左侧
        sliderbar.addEventListener('mouseenter', function () {
            animate(con, -160, function () {
                sliderbar.children[0].innerHTML = '→';
            });
        });
        // 当我们鼠标离开 sliderbar 就会让 con这个盒子滑动到右侧
        sliderbar.addEventListener('mouseleave', function () {
            animate(con, 0, function () {
                sliderbar.children[0].innerHTML = '⬅';
            });
        });

    </script>
</body>

</html>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值