网页特效a

1. 元素偏移量offset系列

1. offset概述

offset就是偏移量,可以动态得到该元素的位置(偏移)、大小等

  • 获得元素距离带有定位父元素的位置
  • 获得元素自身的大小
  • 注意:返回的数值都不带单位
    offset系列常用属性
offset系列属性作用
element.offsetParent返回作为该元素带有定位的父级元素
element.offsetTop返回元素相对带有定位父元素上方的偏移
element.offsetLeft返回元素相对带有定位父元素左边框的偏移
element.offsetWidth返回自身包括padding、边框、内容区的宽度,返回数值不带单位
element.offsetHeight返回自身包括padding、边框、内容区的高度,返回数值不带单位

获取相对位置


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .father {
            position: relative;
            width: 200px;
            height: 200px;
            background-color: pink;
            margin: 150px;
        }

        .son {
            width: 100px;
            height: 100px;
            background-color: blue;
            margin-left: 45px;

        }

        .w {
            width: 200px;
            height: 200px;
            background-color: yellow;
            padding: 10px;
            border: 15px solid red;
        }
    </style>
</head>

<body>
    <div class="father">
        <div class="son"></div>
    </div>
    <div class="w"></div>

    <script>
        var father = document.querySelector('.father');
        var son = document.querySelector('.son');
        console.log(father.offsetTop);
        console.log(father.offsetLeft);
        //它以带有定位的为准  若父亲没有定 或者没有父亲以body为准
        console.log(son.offsetLeft);
        console.log('----------------');
        var w = document.querySelector('.w')
        //得到元素大小宽度高度,包含padding border
        console.log(w.offsetWidth);
        console.log(w.offsetHeight);

        console.log('---------------');
        //返回带有定位的父亲  否则返回body
        console.log(son.offsetParent);  //只返回带有定位的父亲
        console.log(son.parentNode);    //返回父亲 最近一级 不管有没有定位
    </script>
</body>

</html>

2.offset与style区别

offsetstyle
可以得到任意样式表中的样式值只能得到行内样式表中的值
获取的数值没有单位style.width获取的值是有单位的字符串
offsetWidth包含padding+border+widthstyle.width获得不包含padding和border值
offsetWidth等属性是只读属性,只能获取不能赋值style.width获取的值是可读写,可以获取也可以赋值
所以,获取元素大小位置,用offset更合适所以,我们想给元素赋值、更改,需要用style改变
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {
            width: 200px;
            height: 200px;
            background-color: pink;
            padding: 10px;
        }
    </style>
</head>

<body>
    <div class="box" style="width:200px"></div>

    <script>
        var box = document.querySelector('.box');
        console.log(box.offsetWidth);
        //内嵌样式表不能获取
        console.log(box.style.width);
    </script>
</body>

</html>

案例

获取鼠标在盒子中的坐标

  1. 在盒子点击,想要得到距离盒子的距离
  2. 得到鼠标距离页面的距离
  3. 得到盒子在页面的距离
  4. 相减得到鼠标在盒子中的坐标
  5. 如果想移动以下鼠标,就获取坐标,使用鼠标移动事件 mousemove
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            border: 0;
        }

        .box {
            width: 200px;
            height: 200px;
            background-color: pink;
            margin: 200px;
        }
    </style>
</head>

<body>
    <div class="box"></div>
    <script>
        // 1. 在盒子点击,想要得到距离盒子的距离
        // 2. 得到鼠标距离页面的距离
        // 3. 得到盒子在页面的距离
        // 4. 相减得到鼠标在盒子中的坐标
        // 如果想移动以下鼠标,就获取坐标,使用鼠标移动事件 mousemove
        var box = document.querySelector('.box');

        box.addEventListener('mousemove', function (e) {
            // var mLeft = e.pageX;
            // var mTop = e.pageY;
            // var bLeft = this.offsetLeft;
            // var bTop = this.offsetTop;
            var x = e.pageX - this.offsetLeft;
            var y = e.pageY - this.offsetTop;
            console.log(x, y);
        })

    </script>

</body>

</html>

拖动的模糊框

弹出框也成为了模态框

  1. 点击弹出层,会弹出模态框,并且像是灰色半透明的遮挡层
  2. 点击关闭按钮可以关闭模态框,并且同事关闭灰色半透明遮挡层
  3. 鼠标放到模态框最上面遗憾,可以按住鼠标拖曳模态框在页面中移动
  4. 鼠标松开可以停止模态框移动
  5. 拖拽过程:鼠标移动过程中,获得新的值付给模态框的left和top值,模态框就可以跟着鼠标走了
  6. 鼠标按下触发的时间源 是login上面的title
  7. 鼠标的坐标减去鼠标在盒子的坐标,才是模态框真正的位置
  8. 鼠标按下,我们要得到鼠标在盒子的坐标
  9. 鼠标移动,就让模态框坐标设置为 鼠标坐标减去盒子坐标即可,但是移动事件写到按下事件里面。
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .login-header {
            width: 100%;
            text-align: center;
            height: 30px;
            font-size: 24px;
            line-height: 30px;
        }

        ul,
        li,
        ol,
        dl,
        dt,
        dd,
        div,
        p,
        span,
        h1,
        h2,
        h3,
        h4,
        h5,
        h6,
        a {
            padding: 0px;
            margin: 0px;
        }

        .login {
            display: none;
            width: 512px;
            height: 280px;

            position: fixed;
            border: #ebebeb solid 1px;
            left: 50%;
            top: 50%;
            background: #ffffff;
            /* 属性用于在元素的框架上添加阴影效果。你可以在同一个元素上设置多个阴影效果,并用逗号将他们分隔开。 */
            box-shadow: 0px 0px 20px #ddd;
            /* 属性设定了一个定位元素及其后代元素或 flex 项目的 z-order。 当元素之间重叠的时候, z-index 较大的元素会覆盖较小的元素在上层进行显示。 */
            z-index: 9999;
            /* 旋转,缩放,倾斜或平移给定元素。 */
            transform: translate(-50%, -50%);
        }

        .login-title {
            width: 100%;
            margin: 10px 0px 0px 0px;
            text-align: center;
            line-height: 40px;
            height: 40px;
            font-size: 18px;
            position: relative;
            cursor: move;
        }

        .login-input-content {
            margin-top: 20px;
        }

        .login-button {
            width: 50%;
            margin: 30px auto 0px auto;
            line-height: 40px;
            font-size: 14px;
            border: #ebebeb 1px solid;
            text-align: center;
        }

        .login-bg {
            display: none;
            width: 100%;
            height: 100%;
            position: fixed;
            top: 0px;
            left: 0px;
            background: rgba(0, 0, 0, .3);
        }

        a {
            text-decoration: none;
            color: #000000;
        }

        .login-button a {
            display: block;
        }

        .login-input input.list-input {
            float: left;
            line-height: 35px;
            height: 35px;
            width: 350px;
            border: #ebebeb 1px solid;
            text-indent: 5px;
        }

        .login-input {
            overflow: hidden;
            margin: 0px 0px 20px 0px;
        }

        .login-input label {
            float: left;
            width: 90px;
            padding-right: 10px;
            text-align: right;
            line-height: 35px;
            height: 35px;
            font-size: 14px;
        }

        .login-title span {
            position: absolute;
            font-size: 12px;
            right: -20px;
            top: -30px;
            background: #ffffff;
            border: #ebebeb solid 1px;
            width: 40px;
            height: 40px;
            border-radius: 20px;
        }
    </style>
</head>

<body>
    <div class="login-header"><a id="link" href="javascript:;">点击,弹出登录框</a></div>
    <div id="login" class="login">
        <div id="title" class="login-title">登录会员
            <span><a id="closeBtn" href="javascript:void(0);" class="close-login">关闭</a></span>
        </div>
        <div class="login-input-content">
            <div class="login-input">
                <label>用户名:</label>
                <input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input">
            </div>
            <div class="login-input">
                <label>登录密码:</label>
                <input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="list-input">
            </div>
        </div>
        <div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登录会员</a></div>
    </div>
    <!-- 遮盖层 -->
    <div id="bg" class="login-bg"></div>
    <script>
        var login = document.querySelector('.login');
        var mask = document.querySelector('.login-bg');
        var link = document.querySelector('#link');
        var closeBtn = document.querySelector('#closeBtn');
        //1. 做点击显示关闭隐藏
        link.addEventListener('click', function () {
            mask.style.display = 'block';
            login.style.display = 'block';
        })
        closeBtn.addEventListener('click', function () {
            mask.style.display = 'none';
            login.style.display = 'none';
        })

        //2. 拖拽效果
        var title = document.querySelector('#title')
        title.addEventListener('mousedown', function (e) {
            var x = e.pageX - login.offsetLeft;
            var y = e.pageY - login.offsetTop;
            login.addEventListener('mousemove', fn1)
            function fn1(e) {
                this.style.left = e.pageX - x + 'px';
                this.style.top = e.pageY - y + 'px';
            }

            //3. 鼠标弹起  移除鼠标移动事件
            login.addEventListener('mouseup', function () {
                this.removeEventListener('mousemove', fn1)
            })
        })
    </script>
</body>

</html>

模仿京东放大镜效果

window.addEventListener('load', function() {
    var preview_img = document.querySelector('.preview_img');
    var mask = document.querySelector('.mask');
    var big = document.querySelector('.big');
    // 1. 当我们鼠标经过 preview_img 就显示和隐藏 mask 遮挡层 和 big 大盒子
    preview_img.addEventListener('mouseover', function() {
        mask.style.display = 'block';
        big.style.display = 'block';
    })
    preview_img.addEventListener('mouseout', function() {
            mask.style.display = 'none';
            big.style.display = 'none';
        })
        // 2. 鼠标移动的时候,让黄色的盒子跟着鼠标来走
    preview_img.addEventListener('mousemove', function(e) {
        // (1). 先计算出鼠标在盒子内的坐标
        var x = e.pageX - this.offsetLeft;
        var y = e.pageY - this.offsetTop;
        // console.log(x, y);
        // (2) 减去盒子高度 300的一半 是 150 就是我们mask 的最终 left 和top值了
        // (3) 我们mask 移动的距离
        var maskX = x - mask.offsetWidth / 2;
        var maskY = y - mask.offsetHeight / 2;
        // (4) 如果x 坐标小于了0 就让他停在0 的位置
        // 遮挡层的最大移动距离
        var maskMax = preview_img.offsetWidth - mask.offsetWidth;
        if (maskX <= 0) {
            maskX = 0;
        } else if (maskX >= maskMax) {
            maskX = maskMax;
        }
        if (maskY <= 0) {
            maskY = 0;
        } else if (maskY >= maskMax) {
            maskY = maskMax;
        }
        mask.style.left = maskX + 'px';
        mask.style.top = maskY + 'px';
        // 3. 大图片的移动距离 = 遮挡层移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
        // 大图
        var bigIMg = document.querySelector('.bigImg');
        // 大图片最大移动距离
        var bigMax = bigIMg.offsetWidth - big.offsetWidth;
        // 大图片的移动距离 X Y
        var bigX = maskX * bigMax / maskMax;
        var bigY = maskY * bigMax / maskMax;
        bigIMg.style.left = -bigX + 'px';
        bigIMg.style.top = -bigY + 'px';

    })

})

2. 元素可视区client 系列

client翻译是客户端,使用client系列相关的属性来获取元素可视区的相关信息,通过client系列的相关属性可以得到该元素的带下、元素等

client系列属性作用
element.clientTop返回元素上边框的大小
element.clientLeft返回元素左边框的大小
element.clientWidth返回自身包括padding、内容区的宽度、不包含边框、返回属性不带单位
element.clientHeight返回自身包括padding、内容区的高度、不包含边框、返回属性不带单位
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {
            width: 200px;
            height: 200px;
            border: 2px solid red;
            background-color: pink;
            padding: 10px;
            margin: auto;
        }
    </style>
</head>

<body>
    <div class="box"></div>


    <script>

        //client宽度个offsetWidth最大区别client不包含边框
        var box = document.querySelector('.box');
        console.log(box.clientTop);
        console.log(box.clientLeft);
        console.log(box.clientWidth);
        console.log(box.clientHeight);
    </script>
</body>

</html>

案例 淘宝flexible.js源码分析

(function flexible(window, document) {
    // 获取的html 的根元素
    var docEl = document.documentElement
    // dpr 物理像素比
    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))

立即执行函数

意义
立即执行函数最大的作用 独立创建了一个作用域

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        //1. 立即执行函数,不需要调用 立马能够自己执行的函数
        //传统函数
        function fn() {
            console.log(1111);
        }
        fn();
        //2. 立即执行函数写法
        // (function () { })();
        //或者
        // (function () { }());

        (function () {
            console.log(arguments[0], arguments[1], arguments[2]);
        })(1, 2, 3);   //第二个小括号看做调用函数,传到匿名函数(可以写名字)的形参列表

        (function sum() {
            console.log(arguments[0], arguments[1], arguments[2]);
        }(4, 5, 6)) //后面的小括号相当于调用  传参到匿名函数(可以写名字)的形参列表


        //3. 立即执行函数最大的作用  独立创建了一个作用域
    </script>
</body>

</html>

pageshow事件

  1. pageshow和load事件

  2. load事件触发:

    1. a标签的超链接
    2. F5刷新(强制刷新)
    3. 前进后退按钮
  3. 但是在火狐浏览中点击a链接后当前页面存在内存中,当返回时不会触发load事件,所以可以使用pageshow事件进行触发,

  4. pageshow在显示页面时触发,无论页面是否来自缓存。、

  5. 在重新加载页面时pageshow会在load事件触发后触;可以和根据事件对象中的persistd来判断是否是缓存中的页面触发的pageshow事件,注意这个事件给window添加

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        //一般写法,但在火狐中点击超链接返回不会触发
        window.addEventListener('load', function () {
            alert('111');
        })

        //pageshow写法   在火狐中点击超链接返回也会触发
        window.addEventListener('pageshow', function (e) {
            //e.persisted判断页面是否是冲缓存中读取 ,是返回true
            if (e.persisted) {
                alert('12313');
            }
        })
    </script>
</body>

</html>

3. 元素滚动scroll系列

1. 元素scroll系列属性

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

scroll系列属性作用
element.scrollTop返回被卷去的上侧距离,返回数值不带单位
element.scrollLeft返回被卷去的左侧距离,返回数值不带单位
element.scrollWidth返回自身的实际宽度,不含边框,返回数值不带单位
element.scrollHeight返回自身实际的高度,不含边框,返回数值不带单位

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WIjdvODu-1633613557026)(vx_images/1426042181043.png)]

2. 页面被卷去的头部

当页面高度或宽度不足以显示整个页面时,会自动出现滚动条。当滚动条向下滚动式,页面上面被隐藏的高度,就称为被卷去的头部。滚动条在滚动式会触发onscroll事件。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            background-color: pink;
            border: 10px solid red;
            padding: 10PX;
            overflow: auto;
        }
    </style>
</head>

<body>
    <div>
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容


    </div>

    <script>
        //scroll系列
        var div = document.querySelector('div')
        //反回div的height不包含边框包含padding,文本超出部分也算在内
        console.log(div.scrollHeight);
        //返回div的height包含边框padding,文本超出不算在内
        console.log(div.offsetHeight);
        //返回div的height包含padding不包含边框,文本超出不算在内
        console.log(div.clientHeight);
        //scroll滚动事件,滚动条发生变化会触发事件
        div.addEventListener('scroll', function () {
            console.log(div.scrollTop);
        })
    </script>
</body>

</html>

案例 防淘宝固定右侧侧边栏

案例分析

  1. 需要页面滚动事件scroll,事件源是document
  2. 页面被卷进去的头部:可以通过window.pageYOffset获取的,如果被卷去的左侧window.pageYOffset
  3. 注意:元素被卷曲的头部是element.scrollTop,如果是页面被换区的头部则是window.pageYOffset
<!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>
        .slider-bar {
            position: absolute;
            left: 50%;
            top: 300px;
            margin-left: 600px;
            width: 45px;
            height: 130px;
            background-color: pink;
        }

        .w {
            width: 1200px;
            margin: 10px auto;
        }

        .header {
            height: 150px;
            background-color: purple;
        }

        .banner {
            height: 250px;
            background-color: skyblue;
        }

        .main {
            height: 1000px;
            background-color: yellowgreen;
        }

        span {
            display: none;
            position: absolute;
            bottom: 0;
        }
    </style>
</head>

<body>
    <div class="slider-bar">
        <span class="goBack">返回顶部</span>
    </div>
    <div class="header w">头部区域</div>
    <div class="banner w">banner区域</div>
    <div class="main w">主体部分</div>
    <script>
        //1. 获取元素
        var goBack = document.querySelector('.goBack')
        var sliderbar = document.querySelector('.slider-bar');
        var header = document.querySelector('.header')
        var banner = document.querySelector('.banner')
        var main = document.querySelector('.main')
        var mainTop = main.offsetTop;
        //侧边栏原始位置
        var sliderbarTop0 = sliderbar.offsetTop
        //侧边栏固定后所在的位置
        var sliderbarTop = sliderbar.offsetTop - banner.offsetTop + 'px';
        // console.log(header.offsetHeight);
        //2. 页面滚动事件
        document.addEventListener('scroll', function () {
            var y = window.pageYOffset;
            //3 .当我们头部被卷去大于172 侧边栏就更改为固定定位
            if (y >= banner.offsetTop) {
                // console.log(y);
                sliderbar.style.position = 'fixed'
                sliderbar.style.top = sliderbarTop
            } else {
                sliderbar.style.position = 'absolute'
                sliderbar.style.top = '';
            }

            //当卷到主题部位  显示返回顶部

            if (y >= mainTop) {
                goBack.style.display = 'block'
            } else {
                goBack.style.display = 'none'
            }
        })
        //3. 点击返回顶部




    </script>
</body>

</html>

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

  1. 声明了DTD 使用document.documentElement.scrollTop
  2. 未声明DTD使用document.body.scrollTop
  3. 新方法window.pageYOffset和window.pageXOffset,IE开始职称

4. 三大系列总结

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DsfHHAHi-1633613557029)(vx_images/1456616121044.png)]
主要用法

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

4. mouseenter和mouseover的区别

1. mouseenter 鼠标事件

  1. 当鼠标移动到元素上时就会触发mouseenter事件
  2. mouseover鼠标经过自身盒子会触发,经过子盒子还会触发。
  3. mouseenter只经过自身盒子触发
  4. 原因:mouseenter不会冒泡
  5. 跟mouseenter搭配鼠标离开mouseleave 同样也不会冒泡

5. 动画函数封装

1. 动画实现原理

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

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            border: 0;
            padding: 0;
        }

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

<body>
    <div></div>
    <script>
        //动画原理
        // 1. 获得盒子当前位置
        // 2. 让盒子在当我前位置上加1个移动距离
        // 3. 利用定时器不断重复这个操作
        // 4. 加一个结束定时器的条件
        // 5. 注意元素需要添加定位,才能使用element.style.left
        var div = document.querySelector('div');
        console.log(document.body.clientWidth);
        var timer = setInterval(function () {
            //当div跑到右边届停止计时器
            if (div.offsetLeft >= document.body.clientWidth - div.clientWidth) {
                //停止动画 本质是停止定时器
                clearInterval(timer);
            }
            div.style.left = div.offsetLeft + 0.5 + 'px';
        }, 1)


    </script>
</body>

</html>

2. 动画函数的简单封装

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

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            border: 0;
            padding: 0;
        }

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

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

<body>
    <div></div>
    <span></span>
    <script>
        //简单动画封装函数
        //obj目标对象,tage目标位置
        // 给不同元素指定了不同的定时器
        function animate(obj, targe) {
            obj.timer = setInterval(function () {
                //当div跑到右边届停止计时器
                if (obj.offsetLeft >= targe) {
                    //停止动画 本质是停止定时器
                    clearInterval(timer);
                }
                obj.style.left = obj.offsetLeft + 0.5 + 'px';
            }, 1)
        }

        var div = document.querySelector('div')
        var span = document.querySelector('span')
        animate(div, 500)
        animate(span, 600)


    </script>
</body>

</html>

3. 给不同对象添加不同定时器

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            border: 0;
            padding: 0;
        }

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

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

<body>
    <button>点击夏雨荷才走</button>
    <div></div>
    <span>夏雨荷</span>
    <script>
        //简单动画封装函数
        //obj目标对象,tage目标位置
        // 给不同元素指定了不同的定时器
        function animate(obj, targe) {
            //当我们不断点击按钮,元素的速度会越来越快,应为开启了太多定时器
            //解决方案,让我们元素只有一个定时器执行
            //先清除以前的定时器
            clearInterval(clearInterval(obj.timer))
            obj.timer = setInterval(function () {
                //当div跑到右边届停止计时器
                if (obj.offsetLeft >= targe) {
                    //停止动画 本质是停止定时器
                    clearInterval(obj.timer);
                }
                obj.style.left = obj.offsetLeft + 0.5 + 'px';
            }, 1)
        }

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



    </script>
</body>

</html>

4. 5.缓动效果原理

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

  1. 让盒子每次移动的盒子移动距离慢慢变小,速度就会慢慢落下来
  2. 核心算法:(目标值-现在的值)/10 作为每次移动的距离步长
  3. 停止的条件是:让当前盒子位置等于目标位置就停止计时器
  4. 步长值需要取整
  5. 步长值是正的向上取整,步长是负的向下取整
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            border: 0;
            padding: 0;
        }

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

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

<body>
    <button class="btn500">点击夏雨荷到500</button>
    <button class="btn800">点击夏雨荷到800</button>
    <div></div>
    <span>夏雨荷</span>
    <script>
        function animate(obj, targe) {
            clearInterval(clearInterval(obj.timer))
            obj.timer = setInterval(function () {
                //步长值写在定时器中
                //将步长值改为整数 不要出现小数  向上取整
                //当前进时step为正数向上取整
                //当后退时step为负数要向下取整
                var step = (targe - obj.offsetLeft) / 10
                step = step > 0 ? Math.ceil(step) : Math.floor(step)
                if (obj.offsetLeft == targe) {
                    clearInterval(obj.timer);
                }
                //将步长加到style中
                obj.style.left = obj.offsetLeft + step + 'px';
            }, 20)
        }

        var div = document.querySelector('div')
        var span = document.querySelector('span')
        var btn500 = document.querySelector('.btn500');
        var btn800 = document.querySelector('.btn800');
        // animate(div, 1000)
        btn500.addEventListener('click', function () {
            animate(span, 500)
        })
        btn800.addEventListener('click', function () {
            animate(span, 800)
        })



    </script>
</body>

</html>

6. 动画函数添加回调函数

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

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            border: 0;
            padding: 0;
        }

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

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

<body>
    <button class="btn500">点击夏雨荷到500</button>
    <button class="btn800">点击夏雨荷到800</button>
    <div></div>
    <span>夏雨荷</span>
    <script>
        function animate(obj, targe, callback) {
            // console.log(callback); callback = function(){}  调用时 callback()

            clearInterval(clearInterval(obj.timer))
            obj.timer = setInterval(function () {
                //步长值写在定时器中
                //将步长值改为整数 不要出现小数  向上取整
                //当前进时step为正数向上取整
                //当后退时step为负数要向下取整
                var step = (targe - obj.offsetLeft) / 10
                step = step > 0 ? Math.ceil(step) : Math.floor(step)
                if (obj.offsetLeft == targe) {
                    clearInterval(obj.timer);
                    //回调函数写到定时器结束里面
                    if (callback) {
                        callback(); //调用函数
                    }
                }
                //将步长加到style中
                obj.style.left = obj.offsetLeft + step + 'px';
            }, 20)
        }

        var div = document.querySelector('div')
        var span = document.querySelector('span')
        var btn500 = document.querySelector('.btn500');
        var btn800 = document.querySelector('.btn800');
        // animate(div, 1000)
        btn500.addEventListener('click', function () {
            animate(span, 500)
        })
        btn800.addEventListener('click', function () {
            //添加回调函数
            animate(span, 800, function () {
                span.style.backgroundColor = "red"
            })
        })
    </script>
</body>

</html> 

7. 动画函数封装到单独的JS文件中

使用时引入这个JS文件即可

  1. 单独创建一个JS文件
function animate(obj, targe, callback) {
    // console.log(callback); callback = function(){}  调用时 callback()

    clearInterval(clearInterval(obj.timer))
    obj.timer = setInterval(function () {
        //步长值写在定时器中
        //将步长值改为整数 不要出现小数  向上取整
        //当前进时step为正数向上取整
        //当后退时step为负数要向下取整
        var step = (targe - obj.offsetLeft) / 10
        step = step > 0 ? Math.ceil(step) : Math.floor(step)
        if (obj.offsetLeft == targe) {
            clearInterval(obj.timer);
            //回调函数写到定时器结束里面
            if (callback) {
                callback(); //调用函数
            }
        }
        //将步长加到style中
        obj.style.left = obj.offsetLeft + step + 'px';
    }, 20)
}

8. 引入动画函数

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=
    , initial-scale=1.0">
    <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>
    <!-- 引入动画js -->
    </style>
    <script src="animate.js"></script>
</head>

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

    <script>
        //当鼠标经过sliderbar  就让盒子con滑动到左侧
        //当鼠标离开sliderbar  就让盒子con滑动到右侧

        //1. 获取元素
        var sliderbar = document.querySelector(".sliderbar")
        var con = document.querySelector(".con");


        sliderbar.addEventListener('mouseenter', function () {
            // animate(obj,target,callback)
            animate(con, -160, function () {
                //当我们动画执行完毕将左箭头,改为右箭头
                sliderbar.children[0].innerHTML = '→'
            });
        });
        sliderbar.addEventListener('mouseleave', function () {
            animate(con, 0, function () {
                sliderbar.children[0].innerHTML = '←'
            })
        })
    </script>
</body>

</html>

6.常见网页特效

案例 网页轮播图

鼠标经过显示隐藏两侧箭头

案例分析

  1. 因js文件较多,单独创建js文件,再引入
  2. 此时需要添加load事件
  3. 鼠标经过轮播图模块,左右按钮显示,离开隐藏
  4. 显示隐藏display按钮

动态生成小圆圈

案例分析

  1. 动态生成小圆圈
  2. 核心思路:小圆圈的个数要跟图片张数一致
  3. 先得到ul里的图片张数(ul中li的个数)
  4. 利用循环动态生成小圆圈(放入ol中)
  5. 创建节点createElement(‘li’)
  6. 插入节点ol.appendChild(li)
  7. 让第一个小圆圈添加current类

小圆圈排他思想

案例分析

  1. 小圆圈排他思想
  2. 点击当前小圆圈,就添加current类
  3. 其余小圆圈移除这个current类

点击小圆圈滚动图片

案例分析

  1. 点击小圆圈滚动图片
  2. 此时用到animate动画函数,将js文件引入(注意,因为index.js依赖animate.js,所以anmate.js要在index.js上面引入)
  3. 使用动画函数的前提,必须有定位
  4. 注意是ul移动而不是li
  5. 滚动图片的核心算法:点击某个小圆圈,就让图片滚动 小圆圈的索引号*图片的宽度作为ul移动距离
  6. 此时需要知道小圆圈索引号,生成小圆圈是,设置一个自定义属性,点击是获取这个自定义属性即可

右侧按钮无缝滚动

案例分析

  1. 点击按钮就让图片滚动一张
  2. 声明一个num变量,点击一次,自增1,让变量乘以图片的宽度就是ul滚动的距离
  3. 图片无缝滚动原理
  4. 把ul第一个li复制一份,放到ul的最后面
  5. 当图片滚到克隆的最后一张图,让ul快速的、不做动画的跳到最左侧:left为0
  6. 同时num设置为0,就可以从新开始滚动图片了

克隆第一张图片

案例分析

  1. 克隆第一章图片
  2. 克隆ul第一个li cloneNode() 加true深克隆,false浅克隆
  3. 添加到ul最后面

小圆圈跟随右侧按钮已一起变化

案例分析

  1. 小圆圈跟随右侧按钮已一起变化
  2. 最简单的方法,声明一个变量circle,每次点击自增1,左侧按钮也需要这个变量,声明全局变量
  3. 但是图片有5张,我们小圆圈只有4个,必须加一个判断条件
  4. 如果circle=4就重新恢复为0

左侧按钮功能制作

自动播放功能

案例分析

  1. 自动播放
  2. 添加一个计时器
  3. 自动轮播相当于点击了右侧按钮
  4. 此时我们手动调用右侧按钮点击事件 arrow_r.click();
  5. 鼠标经过focus就停止计时器
  6. 鼠标离开就开启定时器

案例源码 在day9 19

1. 节流阀

防止轮播图连续点击造成过快播放
目的:当上一个函数动画内容执行完毕,再去执行下一函数动画,让时间无法连续触发
核心思路:通过回调函数,添加一个变量来控制,锁住函数和解锁函数
开始设置一个变量 var flag = true;
if(flag){flag = false;do something} 关闭
利用回调函数 动画执行完毕,flag = true 打开

案例 返回顶部

滚动到文档特定位置
window.scroll(x,y)
案例分析

  1. 带有动画的返回顶部
  2. 继续使用我们的封装函数
  3. 只需把left的相关的值改为 垂直滚动的值
  4. 页面滚动了多少可以通过,window.pageYOffset获得
<!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>
        .slider-bar {
            position: absolute;
            left: 50%;
            top: 300px;
            margin-left: 600px;
            width: 45px;
            height: 130px;
            background-color: pink;
        }

        .w {
            width: 1200px;
            margin: 10px auto;
        }

        .header {
            height: 150px;
            background-color: purple;
        }

        .banner {
            height: 250px;
            background-color: skyblue;
        }

        .main {
            height: 1000px;
            background-color: yellowgreen;
        }

        span {
            display: none;
            position: absolute;
            bottom: 0;
        }
    </style>
</head>

<body>
    <div class="slider-bar">
        <span class="goBack">返回顶部</span>
    </div>
    <div class="header w">头部区域</div>
    <div class="banner w">banner区域</div>
    <div class="main w">主体部分</div>
    <script>
        //1. 获取元素
        var goBack = document.querySelector('.goBack')
        var sliderbar = document.querySelector('.slider-bar');
        var header = document.querySelector('.header')
        var banner = document.querySelector('.banner')
        var main = document.querySelector('.main')
        var mainTop = main.offsetTop;
        //侧边栏原始位置
        var sliderbarTop0 = sliderbar.offsetTop
        //侧边栏固定后所在的位置
        var sliderbarTop = sliderbar.offsetTop - banner.offsetTop + 'px';
        // console.log(header.offsetHeight);
        //2. 页面滚动事件
        document.addEventListener('scroll', function () {
            var y = window.pageYOffset;
            //3 .当我们头部被卷去大于172 侧边栏就更改为固定定位
            if (y >= banner.offsetTop) {
                // console.log(y);
                sliderbar.style.position = 'fixed'
                sliderbar.style.top = sliderbarTop
            } else {
                sliderbar.style.position = 'absolute'
                sliderbar.style.top = '';
            }

            //当卷到主题部位  显示返回顶部

            if (y >= mainTop) {
                goBack.style.display = 'block'
            } else {
                goBack.style.display = 'none'
            }
        })
        //3. 点击返回顶部
        goBack.addEventListener('click', function () {
            //里面的x,y不需要单位
            //窗口滚动对象是window
            animate(window, 0);
        })
        //动画函数

        function animate(obj, targe, callback) {
            // console.log(callback); callback = function(){}  调用时 callback()

            clearInterval(clearInterval(obj.timer))
            obj.timer = setInterval(function () {
                //步长值写在定时器中
                //将步长值改为整数 不要出现小数  向上取整
                //当前进时step为正数向上取整
                //当后退时step为负数要向下取整
                var step = (targe - window.pageYOffset) / 10
                step = step > 0 ? Math.ceil(step) : Math.floor(step)
                if (window.pageYOffset == targe) {
                    clearInterval(obj.timer);
                    //回调函数写到定时器结束里面
                    if (callback) {
                        callback(); //调用函数
                    }
                }
                //将步长加到style中
                // window.scroll(0) = window.pageYOffset + step + 'px';
                window.scroll(0, window.pageYOffset + step)
            }, 20)
        }



    </script>
</body>

</html>

案例:筋斗云

鼠标经过某个小li,筋斗云跟到当前li位置
鼠标离开li,鸡斗云复原为原来的位置
鼠标点击了某个li,筋斗云就会停留在这个li位置
案例分析

  1. 利用动画函数做动画效果
  2. 原先筋斗云的起始位置是0
  3. 鼠标经过某个小li,把当前小li的offsetLeft位置作为目标值即可
  4. 鼠标离开某个小li,就把目标值设为0
<!DOCTYPE html>
<html>

<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        * {
            margin: 0;
            padding: 0
        }

        ul {
            list-style: none;
        }

        body {
            background-color: black;
        }

        .c-nav {
            width: 900px;
            height: 42px;
            background: #fff url(images/rss.png) no-repeat right center;
            margin: 100px auto;
            border-radius: 5px;
            position: relative;
        }

        .c-nav ul {
            position: absolute;
        }

        .c-nav li {
            float: left;
            width: 83px;
            text-align: center;
            line-height: 42px;
        }

        .c-nav li a {
            color: #333;
            text-decoration: none;
            display: inline-block;
            height: 42px;
        }

        .c-nav li a:hover {
            color: white;
        }

        .c-nav li.current a {
            color: #0dff1d;
        }

        .cloud {
            position: absolute;
            left: 0;
            top: 0;
            width: 83px;
            height: 42px;
            background: url(images/cloud.gif) no-repeat;
        }
    </style>
    <script src="animate.js"></script>
    <script>
        window.addEventListener('load', function () {
            //1. 获取元素
            var cloud = document.querySelector('.cloud')
            var c_nav = document.querySelector('#c_nav')
            var lis = c_nav.querySelectorAll('li')

            //2. 给li绑定事件
            //作为云彩的起始位置
            var vurrent = 0;
            for (var i = 0; i < lis.length; i++) {
                //(1).鼠标经过把小li的值给animate
                lis[i].addEventListener('mouseenter', function () {
                    animate(cloud, this.offsetLeft);
                })
                //2. 鼠标离开 云彩复原为0
                lis[i].addEventListener('mouseleave', function () {
                    animate(cloud, current);
                })
                //3. 鼠标点击,就把当前位置作为目标值
                lis[i].addEventListener('click', function () {
                    current = this.offsetLeft;
                    for (var j = 0; j < lis.length; j++) {
                        lis[j].className = '';

                    }
                    this.className = 'current';
                })
            }
        })
    </script>
</head>

<body>
    <div id="c_nav" class="c-nav">
        <span class="cloud"></span>
        <ul>
            <li class="current"><a href="#">首页新闻</a></li>
            <li><a href="#">师资力量</a></li>
            <li><a href="#">活动策划</a></li>
            <li><a href="#">企业文化</a></li>
            <li><a href="#">招聘信息</a></li>
            <li><a href="#">公司简介</a></li>
            <li><a href="#">我是佩奇</a></li>
            <li><a href="#">啥是佩奇</a></li>
        </ul>
    </div>
</body>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值