javascript二——PC端网页特效

元素偏移量offset系列

概述

offset,偏移量,使用offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。

  • 获得元素距离带有定位父元素的位置
  • 获得元素自身的大小(宽度高度)
  • **注:**返回的值都不带单位

offset常见属性

属性作用
element.offsetParent返回作为该元素带有定位的父级元素 如果父级元素都没有定位则返回body
element.offsetTop返回元素相对带有定位父元素上方的偏移
element.offsetLeft返回元素相对带有定位父元素左边框的偏移
element.offsetWidth返回自身包括padding、边框、内容区的高度,不带单位
element.offsetHeight返回自身包括padding、边框、内容区的高度,不带单位
<style>
    * {
        margin: 0;
        padding: 0;
    }
    
    .father {
        width: 200px;
        height: 200px;
        background-color: pink;
        margin: 100px;
        position: relative;
    }
    
    .son {
        width: 100px;
        height: 100px;
        background-color: purple;
        margin-left: 45px;
    }
    
    .box {
        width: 200px;
        height: 200px;
        background-color: skyblue;
    }
</style>

<body>
    <div class="father">
        <div class="son"></div>
    </div>
    <div class="box"></div>
    <script>
        var father = document.querySelector('.father');
        var son = document.querySelector('.son');
        //1. 可以得到元素的偏移 位置 返回的不带单位的数值
        console.log(father.offsetTop); //100
        console.log(father.offsetLeft); //100
        //以带有定位的父亲为准,若父无定位,以body
        console.log(son.offsetTop); //100
        console.log(son.offsetLeft); //145
        //加定位后分别为0、45

        //2. 可以得到元素的大小和宽高
        //包含padding, border, width
        var box = document.querySelector('.box');
        console.log(box.offsetWidth);
        console.log(box.offsetHeight);

        //3. 返回带有定位的父亲,否则返回body
        console.log(son.offsetParent); //必须带定位的父亲
        console.log(son.parentNode); //返回最近一级的父亲(亲爸爸) 不管有无定位
        console.log(box.offsetParent); //<body></>
    </script>

offset和style区别

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

获取鼠标位置案例

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

<body>
    <div class="box"></div>
    <script>
        var box = document.querySelector('.box');
        box.addEventListener('mousemove', function(e) {
            // console.log(e.pageX);
            // console.log(e.pageY);
            var x = e.pageX - this.offsetLeft;
            var y = e.pageY - this.offsetTop;
            this.innerHTML = 'x:' + x + ',y:' + y;
        })
    </script>

拖拽模态框案例

<style>
    .login {
        display: none;
        width: 513px;
        height: 280px;
        position: fixed;
        border: #ebebeb solid 1px;
        left: 50%;
        top: 50%;
        background-color: #fff;
        box-shadow: 0 0 20px #ddd;
        z-index: 9999;
        transform: translate(-50%, -50%);
    }
    
    .login-bg {
        display: none;
        width: 100%;
        height: 100%;
        position: fixed;
        top: 0;
        left: 0;
        background: rgba(0, 0, 0, .3);
    }
    
    .title {
        width: 100%;
        height: 50px;
        line-height: 50px;
        background-color: #ddd;
        font-size: 25px;
        text-align: center;
    }
</style>

<body>
    <div class="login-header">
        <a href="javascript:;" id="link">点击弹出登录框</a>
    </div>
    <div class="login" id="login">
        <div class="title" id="title">会员登录
            <span><a id="closeBtn" href="javascript:void(0)" class="close-btn">关闭</a></span>
        </div>

        <div class="uname">
            <label>用户名:</label>
            <input type="text" placeholder="请输入用户名">
        </div>
        <div class="pwd">
            <label>密码:</label>
            <input type="password" placeholder="请输入密码">
        </div>
    </div>
    <!-- 遮罩层 -->
    <div id="bg" class="login-bg"></div>
</body>
<script>
    var login = document.querySelector('.login');
    var mask = document.querySelector('.login-bg');
    var link = document.querySelector('#link');
    var closeBtn = document.querySelector('#closeBtn');
    var title = document.querySelector('#title');
    link.addEventListener('click', function() {
        mask.style.display = 'block';
        login.style.display = 'block';
    })
    closeBtn.addEventListener('click', function() {
            mask.style.display = 'none';
            login.style.display = 'none';
        })
        //拖拽
        //1.鼠标按下,就获得鼠标在盒子内的坐标
    title.addEventListener('mousedown', function(e) {
        var x = e.pageX - login.offsetLeft;
        var y = e.pageY - login.offsetTop;
        //2.鼠标移动的时候,把鼠标在页面中的坐标,减去鼠标在盒子内的坐标就是模态框的left和tp值
        //document:任何一个地方
        document.addEventListener('mousemove', move)

        function move(e) {
            login.style.left = e.pageX - x + 'px';
            login.style.top = e.pageY - y + 'px';
        }
        //3.鼠标弹起,移除move事件
        document.addEventListener('mouseup', function() {
            document.removeEventListener('mousemove', move);
        })
    })
</script>

放大镜案例

<style>
    .preimg {
        width: 300px;
        height: 150px;
        position: relative;
        border: 1px solid #ccc;
    }
    
    .mask {
        width: 100px;
        height: 100px;
        background-color: goldenrod;
        opacity: .3;
        position: absolute;
        top: 0;
        left: 0;
        cursor: move;
        display: none;
    }
    
    .big {
        width: 400px;
        height: 400px;
        background-color: purple;
        position: absolute;
        left: 310px;
        top: 0;
        z-index: 999;
        display: none;
        border: 1px solid #ccc;
        overflow: hidden;
    }
    
    .bigImg {
        position: absolute;
        left: 0;
        top: 0;
    }
</style>

<body>
    <div class="preimg">
        <img src="../../images/憨桃琳.jpg" alt="" width="300" height="150">
        <div class="mask"></div>
    </div>
    <div class="big">
        <img src="../../images/憨桃琳.jpg" class="bigImg" alt="" width="600" height="300">
    </div>
</body>
<script>
    window.addEventListener('load', function() {
        var preimg = document.querySelector('.preimg');
        var mask = document.querySelector('.mask');
        var big = document.querySelector('.big');
        //鼠标经过:显示隐藏
        preimg.addEventListener('mouseover', function() {
            mask.style.display = 'block';
            big.style.display = 'block';
        })
        preimg.addEventListener('mouseout', function() {
            mask.style.display = 'none';
            big.style.display = 'none';
        })
        preimg.addEventListener('mousemove', function(e) {
            //先计算出鼠标在盒子内的坐标
            var x = e.pageX - this.offsetLeft;
            var y = e.pageY - this.offsetTop;
            //mask移动的距离
            var maskX = x - (mask.offsetWidth / 2);
            var maskY = y - (mask.offsetHeight / 2)
                //x<0;停在0
            if (maskX <= 0) {
                maskX = 0;
            } else if (maskX > preimg.offsetWidth - mask.offsetWidth) {
                maskX = preimg.offsetWidth - mask.offsetWidth
            }
            if (maskY <= 0) {
                maskY = 0;
            } else if (maskY > preimg.offsetHeight - mask.offsetHeight) {
                maskY = preimg.offsetHeight - mask.offsetHeight
            }
            mask.style.left = maskX + 'px';
            mask.style.top = maskY + 'px';
            //
            var bigImg = document.querySelector('.bigImg');
            //大图最大移动距离
            var bigMaxX = bigImg.offsetWidth - big.offsetWidth;
            var bigMaxY = bigImg.offsetWidth - big.offsetWidth;
            //大图移动距离
            var bigX = maskX * bigMaxX / (preimg.offsetWidth - mask.offsetWidth);
            var bigY = maskY * bigMaxY / (preimg.offsetHeight - mask.offsetHeight);
            bigImg.style.left = -bigX + 'px';
            bigImg.style.top = -bigY + 'px';
        })
    })
</script>

元素可视区client系列

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

client系列属性作用
element.clientTop返回边框上边框的大小
element.clientLeft返回元素左边框的大小
element.clientWidth返回自身包括padding、内容区的高度,不含边框,返回数值不带单位
element.clientHeight返回自身包括padding、内容区的高度,不含边框,返回数值不带单位
<style>
    div {
        width: 200px;
        height: 200px;
        background-color: pink;
    }
</style>

<body>
    <div></div>
    <script>
        //client宽度
        var div = document.querySelector('div');
        console.log(div.clientLeft); //0
        console.log(div.clientTop); //0
        console.log(div.clientHeight); //200
        console.log(div.clientWidth); //200
    </script>

立即执行函数

        //1. 立即执行函数:不需要调用,立马能够自己执行的函数
        //2.写法
        // (function(){})() 或者 (function(){}())
        //也可以传参
        (function(a, b) {
            console.log(a + b); //3
        })(1, 2); //第二个()可以看作是调用函数

        (function sum(a, b) {
            console.log(a + b); //7
        }(3, 4))
        //3.立即执行函数最大的作用就是 独立创建一个作用域

淘宝flexibleJS源码分析

(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))

元素滚动scroll系列

我们使用scroll系列的相关属性可以动痞的得到该元素的大小、滚动距离等。

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

<body>
    <div>
        hello
    </div>
    <script>
        var div = document.querySelector('div');
        console.log(div.scrollHeight); //实际内容高度
        console.log(div.clientHeight);
        //scroll: 滚动条发生变化触发的事件
        div.addEventListener('scroll', function() {
            console.log(div.scrollTop);
        })
    </script>

固定侧边栏

页面被卷去的头部:可以通过window.pageYOffset 获得︰如果是被卷去的左侧window.pageXOffset

注意:元素被卷去的头部是element.scrollTop ,如果是页面被卷去的头部则是window.pageYOffset

<style>
    html,
    body {
        scroll-behavior: smooth;
    }
    
    .header {
        width: 80%;
        height: 100px;
        background-color: pink;
        margin: 0 auto;
    }
    
    .banner {
        width: 80%;
        height: 200px;
        background-color: purple;
        margin: 20px auto;
    }
    
    .main {
        width: 80%;
        height: 1000px;
        background-color: skyblue;
        margin: 20px auto;
    }
    
    .w {
        text-align: center;
        font-size: 30px;
        font-weight: bold;
    }
    
    .slider-bar {
        width: 50px;
        height: 200px;
        background-color: red;
        position: absolute;
        right: 0;
        top: 300px;
    }
    
    span {
        display: none;
        position: absolute;
        bottom: 0;
    }
</style>

<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>
        var sliderbar = document.querySelector('.slider-bar');
        var banner = document.querySelector('.banner');
        var span = document.querySelector('.goBack');
        var main = document.querySelector('.main');
        var mainTop = main.offsetTop;
        //侧边栏固定后应该变化的值
        var bannerTop = banner.offsetTop;
        //被卷去头部的大小
        var sliderbarTop = sliderbar.offsetTop - bannerTop;
        //2.页面滚动事件scroll 事件源是document
        document.addEventListener('scroll', function() {
            // console.log(window.pageYOffset);
            if (window.pageYOffset >= bannerTop) {
                sliderbar.style.position = 'fixed';
                sliderbar.style.top = sliderbarTop + 'px';
            } else {
                sliderbar.style.position = 'absolute';
                sliderbar.style.top = '300px';
            }
            //4.到main显示goback
            if (window.pageYOffset >= mainTop) {
                span.style.display = 'block';
            } else {
                span.style.display = 'none';
            }
        });
        span.addEventListener('click', function() {
            window.scrollTo(0, 0);

        })
    </script>

三大系列总结

大小对比作用
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鼠标事件

  • 鼠标移动到元素上时就会触发
  • 类似 mouseover,它们两者之间的差别是
  • mouseover鼠标经过自身盒子会触发,经过子盒子还会触发。mouseenter 只会经过自身盒子触发
  • 因为mouseenter不会冒泡
  • 跟mouseenter搭配鼠标离开mouseleave同样不会冒泡
<style>
    .father {
        width: 300px;
        height: 300px;
        background-color: pink;
    }
    
    .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(11);
            })
            //over在son也触发,enter不触发
    </script>

动画函数封装

动画实现原理

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

实现步骤:

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

封装

<style>
    div {
        width: 200px;
        height: 200px;
        background-color: pink;
        position: absolute;
    }
    
    span {
        width: 300px;
        height: 300px;
        background-color: purple;
        position: absolute;
        top: 300px;
    }
</style>

<body>
    <div></div>
    <span>feliks</span>
    <script>
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        //动画封装obj:目标对象,target:目标位置
        function animate(obj, target) {
            var timer = setInterval(function() {
                if (obj.offsetLeft >= target) {
                    clearInterval(timer);
                }
                obj.style.left = obj.offsetLeft + 5 + "px";
            }, 30)
        }
        animate(div, 200);
        animate(span, 300);
    </script>

优化

    <button>点击我才走</button>
    <script>
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        var btn = document.querySelector('button');
        //动画封装obj:目标对象,target:目标位置
        function animate(obj, target) {
            //不断点击按钮,速度会越来越快,因为开启了太多定时器
            //解决:先清除之前的定时器
            obj.timer = setInterval(function() {
                if (obj.offsetLeft >= target) {
                    clearInterval(obj.timer);
                }
                obj.style.left = obj.offsetLeft + 5 + "px";
            }, 30)
        }
        animate(div, 200);
        btn.addEventListener('click', function() {
            animate(span, 300);
        })
    </script>

缓动效果原理

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

思路:

  1. 让盒子每次移动的距离慢慢变小
  2. 算法:(目标值-现在的值)/10 作为每次移动的距离步长
  3. 停止条件:当前位置=目标位置
    <div></div>
    <span>feliks</span>
    <button>点击我才走</button>
    <script>
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        var btn = document.querySelector('button');
        //动画封装obj:目标对象,target:目标位置
        function animate(obj, target) {
            clearInterval(obj.timer);
            //不断点击按钮,速度会越来越快,因为开启了太多定时器
            //解决:先清除之前的定时器
            obj.timer = setInterval(function() {
                //步长写在定时器里里面
                var step = (target - obj.offsetLeft) / 10;
                if (obj.offsetLeft == target) {
                    clearInterval(obj.timer);
                }

                //把每次加 改成慢慢变小的值
                obj.style.left = obj.offsetLeft + step + "px";
            }, 15)
        }
        animate(div, 400);
        btn.addEventListener('click', function() {
            animate(span, 500);
        })
    </script>
  • 匀速动画 就是 盒子当前的位置 + 固定的值
  • 缓动动画 就是 盒子当前的位置 + 变化的值(目标-当前)/10

动画函数多个目标值之间移动

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

点击时,判断步长是正还是负

  • 正,向上取整
  • 负,向下取整
    <div></div>
    <span>feliks</span>
    <button class="btn500">点击走500</button>
    <button class="btn800">点击走800</button>
    <script>
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        var btn500 = document.querySelector('.btn500');
        var btn800 = document.querySelector('.btn800');
        //动画封装obj:目标对象,target:目标位置
        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);
                }
                //把每次加 改成慢慢变小的值
                obj.style.left = obj.offsetLeft + step + "px";
            }, 15)
        }
        animate(div, 400);
        btn500.addEventListener('click', function() {
            animate(span, 500);
        })
        btn800.addEventListener('click', function() {
            animate(span, 800);
        })
    </script>

动画函数添加回调函数

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

    <button class="btn800">点击走800</button>
    <script>
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        var btn500 = document.querySelector('.btn500');
        var btn800 = document.querySelector('.btn800');
        //动画封装obj:目标对象,target:目标位置
        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);
                    //回调函数写在定时器结束里面
                    if (callback) {
                        callback();
                    }
                }
                //把每次加 改成慢慢变小的值
                obj.style.left = obj.offsetLeft + step + "px";
            }, 15)
        }

        animate(div, 400);
        btn500.addEventListener('click', function() {
            animate(span, 500);
        })
        btn800.addEventListener('click', function() {
            animate(span, 800, function() {
                span.style.backgroundColor = 'skyblue';
            });
        })
    </script>

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

并使用

    <script src="animate.js"></script>
</head>
<style>
    .sliderbar {
        width: 40px;
        height: 40px;
        background-color: pink;
        position: relative;
        float: right;
        z-index: 99;
    }
    
    .con {
        width: 200px;
        height: 40px;
        background-color: purple;
        position: absolute;
        top: 0;
        left: 0;
        z-index: -1;
        text-align: center;
    }
</style>

<body>
    <div class="sliderbar">
        <span>👈</span>
        <div class="con">问题反馈</div>
    </div>
    <script>
        var sliderbar = document.querySelector('.sliderbar');
        var con = document.querySelector('.con');
        sliderbar.addEventListener('mouseenter', function() {
            animate(con, -160, function() {
                sliderbar.children[0].innerHTML = '👉';
            });
        })
        sliderbar.addEventListener('mouseleave', function() {
            animate(con, 0, function() {
                sliderbar.children[0].innerHTML = '👈';
            });
        })
    </script>
</body>

常见网页特效案例

轮播图

节流阀

利用回调函数,添加一个变量,锁住函数和解锁函数

带有动画的返回顶部

筋斗云

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值