【JavaScript - Web API】PC端网页特效( offset / client / scroll / 动画函数封装 / 网页轮播图案例 )

学习视频以及笔记参考来源:

JavaScript基础语法-dom-bom-js-es6新语法-jQuery-数据可视化echarts黑马pink老师前端入门基础视频教程(500多集)持续_哔哩哔哩_bilibili


一、元素偏移量 offset 系列

1、offset 常用属性

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

注意点:

(1)获取元素距离带有定位父元素的位置,也就是说,得到的是相对于有定位父元素的偏移,如果没有父级或者父级都没有定位,则返回body。

(2)返回的是数值,不带单位。

2、offset 与 style 的区别

 3、案例

3.1 模态框拖拽

效果:按住鼠标可以拖拽模态框移动,鼠标松开,停止模态框移动。

<body>
    <div></div>
    <script>
        // 1. 获取事件
        var div = document.querySelector('div');
        // 2. 当鼠标按下时,获取盒子的 offset = 鼠标相对于页面的距离 - 盒子相对于页面的距离
        div.addEventListener('mousedown', function (e) {
            // 获取鼠标点击位置相对于盒子的 offset
            var x_offset = e.pageX - div.offsetLeft;
            var y_offset = e.pageY - div.offsetTop;
            // 定义一个鼠标移动事件
            document.addEventListener('mousemove', move);
            function move(e) {
                // 固定鼠标相对于盒子的距离,动态计算盒子相对于页面的距离并将值赋值为盒子
                var x_box = e.pageX - x_offset;
                var y_box = e.pageY - y_offset;
                div.style.marginLeft = x_box + 'px';
                div.style.marginTop = y_box + 'px';
            }
            // 当鼠标弹起时,删除鼠标移动事件
            document.addEventListener('mouseup', function () {
                document.removeEventListener('mousemove', move);
            })
        })
    </script>
</body>

3.2 仿京东放大镜

效果:仿造京东物品详情页放大展示效果。

案例展示效果:图片是随便找的图 and 鼠标截图的时候显示不出来,大概是这样。

三个模块:

        (1)鼠标经过小图片盒子,黄色的遮挡层和大图片盒子显示,离开隐藏这两个盒子。

        (2)黄色的遮挡层跟随鼠标功能,并且黄色遮挡层不会超过小图片盒子。

        (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;
            padding: 0;
        }

        .small {
            position: relative;
            width: 300px;
            height: 200px;
            margin: 200px 300px;
            cursor: move;
        }

        .small img {
            width: 100%;
            height: 100%;
        }

        .mask {
            display: none;
            position: absolute;
            top: 0;
            left: 0;
            width: 150px;
            height: 150px;
            background-color: antiquewhite;
            /* 设置透明度 */
            opacity: .5;
        }

        .big {
            display: none;
            position: absolute;
            top: 0;
            left: 310px;
            height: 450px;
            width: 450px;
            overflow: hidden;
            border: 1px solid #ccc;
        }

        .big img {
            position: absolute;
            top: 0;
            left: 0;
            width: 900px;
            height: 600px;
        }
    </style>
</head>

<body>
    <div class="small">
        <img src="images/desktop_6.jpg" alt="">
        <!-- 遮挡层 -->
        <div class="mask"></div>
        <!-- 放大后的图片 -->
        <div class="big">
            <img src="images/desktop_6.jpg" alt="">
        </div>
    </div>
    <script>
        var small = document.querySelector('.small');
        var mask = document.querySelector('.mask');
        var big = document.querySelector('.big');
        var big_img = big.querySelector('img');
        console.log(big_img);

        small.addEventListener('mousemove', function (e) {
            mask.style.display = 'block';
            big.style.display = 'block';
            // 1. 实现遮挡层可以跟随鼠标移动
            // 1.1 获取鼠标相对于 small 盒子的 offset,并将值赋值给 mask
            var x_mask_small = e.pageX - small.offsetLeft - mask.offsetWidth / 2;
            var y_mask_small = e.pageY - small.offsetTop - mask.offsetHeight / 2;
            // 1.2 保证 mask 不会超出图片,要加上一些限制条件
            if (x_mask_small <= 0) {
                x_mask_small = 0;
            } else if (x_mask_small >= this.offsetWidth - mask.offsetWidth) {
                x_mask_small = this.offsetWidth - mask.offsetWidth;
            }
            if (y_mask_small <= 0) {
                y_mask_small = 0;
            } else if (y_mask_small >= this.offsetHeight - mask.offsetHeight) {
                y_mask_small = this.offsetHeight - mask.offsetHeight;
            }
            mask.style.left = x_mask_small + 'px';
            mask.style.top = y_mask_small + 'px';

            // 2. 实现大图的放大展示效果
            // 2.1 我这里的 small 图和 big 图是等比例的,因此我直接将之前获取的偏移值*比例得到大图的偏移值
            var x_big = x_mask_small * (big.offsetWidth / this.offsetWidth);
            var y_big = y_mask_small * (big.offsetHeight / this.offsetHeight);
            // 2.2 将获取的偏移值赋值给 big 图的定位参数 left / top (加了定位,不加定位不能用哈)
            big_img.style.left = - x_big + 'px';
            big_img.style.top = - y_big + 'px';
        })
        // 3. 实现放大效果的显示与隐藏
        small.addEventListener('mouseout', function () {
            mask.style.display = 'none';
            big.style.display = 'none';
        })
    </script>
</body>
</html>

二、元素可视区 client 系列

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

三、元素滚动 scroll 系列

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

1、scroll 系列属性

2、页面被卷去的头部

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

  • 页面被卷去的头部可以通过 window.pageYOffset 获得;如果是被卷去的左侧 window.pageXOffset。
  • 元素被卷去的头部是 element.scrollTop , 如果是页面被卷去的头部 则是 window.pageYOffset。

四、offset / client / scroll 对比

 区别:(1)offset 包括 padding 、边框等宽度,client 与 scroll 则不包含。

            (2)如果内容超出盒子,scroll 可以获取滚动距离,而其他两个不行。

主要用法:

 (1)offset系列经常用于获得元素位置:offsetLeft  / offsetTop

 (2)client 经常用于获取元素大小:clientWidth  / clientHeight

 (3)scroll 经常用于获取滚动距离:scrollTop  / scrollLeft

 (4)注意页面滚动的距离通过 window.pageXOffset 获得。

五、动画函数封装

1、原理

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

        实现步骤:(1)获取盒子当前位置。(2)在盒子当前位置的基础上加上步长。(3)利用定时器不断重复 2 的操作。(4)增加结束定时器的条件。

        注意:此元素需要添加定位,才能使用 element.style.left 。

2、动画函数的简单封装

        给函数传递2个参数:动画对象和目标位置。

// 动画对象:obj ; 目标位置:target ; 
function animate(obj, target) {
    // 步长 step
    var step = 5;
    // 利用定时器重复操作
    obj.timer = setInterval(function () {
        // 获取当前位置:obj.offsetLeft
        if (obj.offsetLeft > target) {
            clearInterval(obj.timer);
        } else {
            // 可以通过修改步长 step 实现不同速度的动画
            obj.style.left = obj.offsetLeft + step + 'px';
        }
    }, 50)
}

// 调用函数
animate(div, 300);

3、给动画函数添加回调函数

// 动画对象:obj ; 目标位置:target ; 回调函数 callback
function animate(obj, target, callback) {
    obj.timer = setInterval(function () {
        if (obj.offsetLeft > target) {
            clearInterval(obj.timer);
            if (callback) {
                // 调用回调函数
                callback();
            }
        } else {
            obj.style.left = obj.offsetLeft + 5 + 'px';
        }
    }, 50)
}

// 调用函数
animate(div, 300, function() {});

六、案例:网页轮播图

1、 效果

2、 功能需求

(1)鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。

(2)点击右侧按钮一次,图片往左播放一张,以此类推, 左侧按钮同理。

(3)图片播放的同时,下面小圆圈模块跟随一起变化。

(4)点击小圆圈,可以播放相应图片。

(5)鼠标不经过轮播图, 轮播图也会自动播放图片。

(6)鼠标经过,轮播图模块, 自动播放停止。

案例分析:

        是 ppt 里面直接截取的,我自己写代码的时候可能有一些细节不同,名字取得也不一样,主要是可以参考一下思路,感觉写的还是比较清晰的。

3、 实现的代码

        这部分的代码主要是参照视频的思路来写的,但是我没有视频中的CSS案例,所以自己先写了一个简单的CSS和HTML的界面,再进行JS的实现,具体 code 如下:

<!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;
        }

        li {
            list-style: none;
        }

        .box {
            position: relative;
            width: 1280px;
            height: 720px;
            margin: 200px auto;
            border: 1px solid #ccc;
            overflow: hidden;
        }

        .box .conpic {
            position: absolute;
            top: 0;
            left: 0;
            width: 500%;
        }

        .box .conpic li img {
            float: left;
            width: 1280px;
            height: 720px;
        }

        .forward,
        .backward {
            display: none;
            position: absolute;
            width: 60px;
            height: 80px;
            top: 50%;
            left: 0;
            background-color: rgb(204, 204, 204, .8);
            border-radius: 0 35px 35px 0;
            text-align: center;
            line-height: 80px;
            font-size: 30px;
            cursor: pointer;
            z-index: 666;
        }

        .forward {
            left: 1220px;
            border-radius: 35px 0 0 35px;
        }

        .circle {
            position: absolute;
            top: 92%;
            left: 600px;
        }

        .circle li {
            float: left;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background-color: aliceblue;
            margin: 6px;
        }

        .circle .cirselect {
            /* background-color: bisque; */
            background-color: red;
        }
    </style>

</head>

<body>
    <!-- 搭建结构 -->
    <div class="box">
        <div class="forward">&gt</div>
        <div class="backward">&lt</div>
        <ul class="conpic">
            <li>
                <img src="images/desktop_9.jpg" alt="">
            </li>
            <li>
                <img src="images/desktop_7.jpg" alt="">
            </li>
            <li>
                <img src="images/desktop_8.jpg" alt="">
            </li>
        </ul>
        <ul class="circle">
        </ul>
    </div>

    <script>
        var box = document.querySelector('.box');
        var ul_img = document.querySelector('.conpic');
        var forward = document.querySelector('.forward');
        var backward = document.querySelector('.backward');

        var sigwidth = ul_img.children[0].children[0].offsetWidth;

        // 1. 鼠标经过显示左右按钮
        box.addEventListener('mouseover', function () {
            forward.style.display = 'block';
            backward.style.display = 'block';
            // 当鼠标在图片上则停止自动播放
            clearInterval(timer);
            timer = null;
        })
        box.addEventListener('mouseout', function () {
            forward.style.display = 'none';
            backward.style.display = 'none';
            // 当鼠标离开则继续自动播放
            timer = setInterval(function () {
                // 手动调用时间
                forward.click();
            }, 2000)
        })
        // 2. 动态生成小圆圈
        var ul_circle = document.querySelector('.circle');
        for (var i = 0; i < ul_img.children.length; i++) {
            // 创建一个 li
            var li = document.createElement('li');
            // 将 li 插入到 ul 当中
            ul_circle.appendChild(li);
            ul_circle.children[0].className = 'cirselect';
            // 给 ul_img 和 ul_circle 都增加 index 属性
            ul_img.children[i].setAttribute('index', i);
            ul_circle.children[i].setAttribute('index', i);

            ul_circle.children[i].addEventListener('click', function () {
                // 排他思想实现小圆圈的选中效果
                for (var j = 0; j < ul_circle.children.length; j++) {
                    ul_circle.children[j].className = '';
                }
                this.className = 'cirselect';
                // 实现小圆圈和图片的对齐 ( 点击小圆圈会出现对应的图片 ) 
                var index = this.getAttribute('index');
                num = index;
                animate(ul_img, -sigwidth * index);
            })
        }

        // 3.左右按钮添加点击事件

        // 复制第一张图片放到最后一张
        var img0 = ul_img.children[0].cloneNode(true);
        ul_img.append(img0);
        console.log(ul_img);
        // 定义右按钮点击事件
        var num = 0;
        // 定义节流阀,防止连续点击图片过快
        var flag = true;
        forward.addEventListener('click', function () {
            if (flag) {
                flag = false;
                if (num == ul_img.children.length - 1) {
                    num = 0;
                    // 让最后一张图片和第一张图片无缝衔接(快速跳转,没有动画)
                    ul_img.style.left = 0;
                }
                // 排他思想实现小圆圈的选中效果
                num++;
                animate(ul_img, -sigwidth * num, callback_flag());
                for (var j = 0; j < ul_circle.children.length; j++) {
                    ul_circle.children[j].className = '';
                }
                var index_num = ul_img.children[num].getAttribute('index');
                ul_circle.children[index_num].className = 'cirselect';
            }
        })
        console.log(num);
        // 定义左按钮点击事件
        backward.addEventListener('click', function () {
            if (flag) {
                flag = false;
                if (num == 0) {
                    num = ul_img.children.length - 1;
                    // 让最后一张图片和第一张图片无缝衔接(快速跳转,没有动画)
                    ul_img.style.left = -num * sigwidth + 'px';
                }
                num--;
                animate(ul_img, -sigwidth * num, callback_flag());
                for (var j = 0; j < ul_circle.children.length; j++) {
                    ul_circle.children[j].className = '';
                }
                var index_num = ul_img.children[num].getAttribute('index');
                ul_circle.children[index_num].className = 'cirselect';
            }
        })

        function animate(obj, target, callback) {
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {
                if (obj.offsetLeft > target) {
                    step = -10;
                } else {
                    step = 10;
                }
                // console.log(obj.offsetLeft, target);
                if (obj.offsetLeft - target == 0) {
                    clearInterval(obj.timer);
                } else {
                    obj.style.left = obj.offsetLeft + step + 'px';
                }
            }, 3)
        }

        // 4. 自动播放轮播图
        var timer = setInterval(function () {
            // 手动调用时间
            forward.click();
        }, 2000)
        // 节流阀
        function callback_flag() {
            flag = true;
        }

    </script>
</body>

</html>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值