JS-PC/MOBILE技巧--PC

一、PC 端网页特效

1、元素偏移量 offset 系列

offset 概述

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

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

offset 系列常用属性:

offset系列属性 作用
element.offsetParent 返回作为该元素带有定位的父级元素,如果父级都没有定位则返回body
element.offsetTop 返回元素相对带有定位元素的父元素上方的偏移
element.offsetLeft 返回元素相对带有定位元素的父元素左边框的偏移
element.offsetWidth 返回自身包括padding、边框、内容区的宽度,返回数值不带单位
element.offsetHeight 返回自身包括padding、边框、内容区的高度,返回数值不带单位

示例:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <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: purple;
            margin-left: 45px;
        }
        .w {
            width: 200px;
            height: 200px;
            background-color: skyblue;
            margin: 0 auto 200px;
            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);
        console.log(son.offsetLeft);

        var w = document.querySelector('.w');
        console.log(w.offsetWidth);
        console.log(w.offsetHeight);

        console.log(son.offsetParent);
        console.log(son.parentNode); // 返回父级(最近一级)
    </script>
</body>
</html>

结果:

offset 与 style 区别

offset

  • offset 可以得到任意样式表中的样式值

  • offset 系列获得的数值是没有单位的

  • offsetWidth 包含padding+border+width

  • 我们想要获取元素大小位置,用offset更合适
    style

  • style 只能得到行内样式表中的样式值

  • style.width 获取的是带有单位的字符串

  • style.width 获得不包含padding和border的值

  • 我们想要给元素更改值,则需要用到style
    示例:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
   <style>
       .box {
           width: 200px;
           height: 200px;
           background-color: pink;
       }
   </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);
       // box.offsetWidth = '300px'; // 不可以
       box.style.width = '300px';
   </script>
</body>
</html>

结果:

2、元素可视区 client 系列

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

示例:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <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;
       }
   </style>
</head>
<body>
   <div></div>
   <script>
       // 不包含边框
       var div = document.querySelector('div');
       console.log(div.clientWidth);
   </script>
</body>
</html>

结果:

3、元素滚动 scroll 系列

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

示例:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <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>
       var div = document.querySelector('div');
       console.log(div.scrollHeight);
       console.log(div.clientHeight);
       // scroll滚动事件
       div.addEventListener('scroll', function() {
           console.log(div.scrollTop);
       })
   </script>
</body>
</html>

结果:

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

写法:

  1. 声明了 DTD,使用 document.documentElement.scrollTop
  2. 未声明 DTD,使用 document.body.scrollTop
  3. 新方法 window.pageYOffset 和 window.pageXOffset,IE9 开始支持
js 复制代码
function getScroll() {
    return {
        left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0,
        top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0
    };
}
// 使用的时候 getScroll().left/top;

mouseenter 和 mouseover 的区别

mouseenter 鼠标事件
  • mouseover 鼠标经过自身盒子会触发,经过子盒子还会触发。mouseenter 只会经过自身盒子触发
  • 原因:mouseenter 不会冒泡
  • 搭配的 mouseleave 同样不会冒泡
    示例:
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
   <style>
       .father {
           width: 300px;
           height: 300px;
           background-color: pink;
           margin: 100px auto;
       }
       .son {
           width: 200px;
           height: 200px;
           background-color: purple;
       }
   </style>
</head>
<body>
   <div class="father">
       <div class="son"></div>
   </div>
   <script>
       var father = document.querySelector('.father');
       var son =document.querySelector('.son');
       father.addEventListener('mouseenter', function() {
           console.log(1);
       })
   </script>
</body>
</html>

4、动画函数封装

动画实现原理

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

实现步骤:

  1. 获得盒子当前位置
  2. 让盒子在当前位置上加上一个移动距离
  3. 利用定时器不断重复这个动作
  4. 添加结束定时器的条件
  5. 注意此元素需要添加定位,才能使用 element.style,left
    示例:
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
   <style>
       div {
           position: absolute;
           left: 0;
           width: 100px;
           height: 100px;
           background-color: pink;
       }
   </style>
</head>
<body>
   <div></div>
   <script>
       // 动画原理
       var div = document.querySelector('div');
       var timer = setInterval(function() {
           if (div.offsetLeft >= 400) {
               clearInterval(timer);
           }  
           div.style.left = div.offsetLeft + 5 + 'px';  
       }, 30);       
   </script>
</body>
</html>
动画函数简单封装

传递两个参数:动画对象和移动到的距离
示例:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
   <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>
</head>
<body>
   <div></div>
   <span></span>
   <script>
       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>
</html>
动画函数给不同元素记录不同定时器

示例:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <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>
</head>
<body>
    <button>点击ABC才走</button>
    <div></div>
    <span>ABC</span>

    <script>
        function animate(obj, target) {
            // 调用多次定时器解决方案
            clearInterval(obj.timer);
            obj.timer = setInterval(function() {
                if (obj.offsetLeft >= target) {
                    clearTimeout(timer);
                }
                obj.style.left = obj.offsetLeft + 1 + 'px';
            }, 30);
        }
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        var btn = document.querySelector('button');
        animate(div, 300);
        btn.addEventListener('click', function() {
            // 如果多次点击,移动速度会加快,原因是开了多重定时器
            animate(span, 200);
        })
    </script>
</body>
</html>
缓动效果原理

思路:

  1. 使盒子移动距离慢慢变小,即速度缓慢下降
  2. 核心算法:(目标值 - 现在的位置)/ 10 作为每次移动距离的步长
  3. 停止的条件:让当前盒子位置等于目标盒子的位置
    示例:
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        span {
            position: absolute;
            left: 0;
            top: 200px;
            display: block;
            width: 150px;
            height: 150px;
            background-color: purple;
        }
    </style>
</head>
<body>
    <button class="btn500">点击 ABC 到500</button>
    <button class="btn800">点击 ABC 到800</button>
    <span>ABC</span>

    <script>
        function animate(obj, target) {
            // 调用多次定时器解决方案
            clearInterval(obj.timer);
            obj.timer = setInterval(function() {
                // 步长(正负取值)
                // var step = Math.ceil((target - obj.offsetLeft) / 10);
                var step = (target - obj.offsetLeft) / 10;
                step = step > 0 ? Math.ceil(step) : Math.floor(step);
                if (obj.offsetLeft == target) {
                    clearTimeout(timer);
                }
                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);
        })
    </script>
</body>
</html>
动函数添加回调函数

示例:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        span {
            position: absolute;
            left: 0;
            top: 200px;
            display: block;
            width: 150px;
            height: 150px;
            background-color: purple;
        }
    </style>
</head>
<body>
    <button class="btn500">点击 ABC 到500</button>
    <button class="btn800">点击 ABC 到800</button>
    <span>ABC</span>

    <script>
        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) {
                    clearTimeout(obj.timer);
                    // 回调函数写在定时器停止条件里
                    if (callback) {
                        callback();
                    }
                }
                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, function() {
                span.style.backgroundColor = 'red';
            });
        })
    </script>
</body>
</html>
动画函数封装到单独JS文件里面

示例:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-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>
    <script src="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.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>
</html>

JS 代码:

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) {
            clearTimeout(obj.timer);
            // 回调函数写在定时器停止条件里
            if (callback) {
                callback();
            }
        }
        obj.style.left = obj.offsetLeft + step + 'px';
    }, 15);
}
相关推荐
对空六课6 小时前
两个统计平台数据不同:用同一时间窗和事件样本做差异定位
大数据·前端·网络·数据库
白帽攻防录13 小时前
SRC 挖洞:PostScript 打印机驱动双 RCE,打印服务器怎么变成内网跳板
开发语言·网络安全·php·内网安全
十年Java程序媛13 小时前
Java枚举Enum完整教程|替代静态常量,开发与面试要点
java·开发语言·spring boot·后端·面试
2603_9651481113 小时前
电商选品调研:通过关键词搜索API获取市场热销商品,结合商品详情API分析竞品卖点与定价
开发语言·数据库·人工智能·python·信息可视化
lpfasd12314 小时前
node-sass 停止维护!老项目迁移 Dart Sass 完整教程
前端·rust·sass
xixiaoyunya14 小时前
Python 异步编程入门:用 asyncio 轻松实现并发任务
开发语言·python·php
学逆向的14 小时前
C 循环结构的执行效率分析
c语言·开发语言·数据结构·网络安全
小坏讲微服务15 小时前
刚发布一个月的JDK 27,为什么我建议你立刻升级?
java·开发语言·spring boot·spring·架构·求职招聘·springboot4
Data analyse45616 小时前
rnweb 回放数据量太大怎么办?分片存储与断点续传的实现思路
前端·网络·算法·数据分析
xiaogai_gai16 小时前
金蝶收料通知单查询策略实战教程:从源系统拉取到中间层落地的完整路径
java·前端·数据库