JS详解 | BOM | 系统性学习 | 无知的我费曼笔记

news2024/11/15 13:38:16

无知的我正在复盘js…
该笔记特点是

  • 重新整理了涉及资料的一些语言描述、排版而使用了自己的描述
  • 对一些地方做了补充说明。比如解释专有名词、类比说明、对比说明、注意事项
  • 提升了总结归纳性。尽可能在每个知识点上都使用一句话 || 关键词概括
  • 更注重在实际上怎么应用
  • 提出并回答了一些问题

文章目录

  • BOM
  • 1 窗口加载事件
  • 2 定时器
    • 2.1 一次定时器
    • 2.2 清除定时器
    • 2.3 重复定时器
    • 2.4 秒杀倒计时案例
    • 2.5 发送短信案例
  • 3 JS同步和异步
  • 4 location对象
    • 4.1 对象属性
      • 4.1.1 5秒后页面跳转案例
      • 4.1.3 不同页面数据传递案例
    • 4.2 对象方法
  • 5 navigator对象
  • 6 history对象
  • 7 offset系列
    • 7.1 属性
    • 7.2 offset和style 的区别
    • 7.3 获取鼠标在盒子内的坐标案例
  • 8 client系列
    • 8.1 属性
    • 8.2 立即执行函数
  • 9 scroll系列
    • 9.1 概述
    • 9.2 固定侧边栏案例
  • 10 mouseenter鼠标事件
  • 11 动画函数
    • 11.1 动画实现原理
    • 11.2 封装动画
    • 11.3 不同元素记录不同的定时器案例
  • 12 缓动动画
    • 12.1 缓动动画原理
    • 12.2 基本代码实现
    • 12.3 实现后退
    • 12.4 回调函数
    • 12.5 侧边栏弹出弹入案例
  • 13 网页轮播图
    • 13.1 功能需求
    • 13.2 基本环境
    • 13.3 鼠标悬浮与离开
    • 13.4 动态小圆圈
    • 13.5 右侧按钮
    • 13.6 克隆第一张图片
    • 13.7 小圆圈跟随
    • 13.8 左侧按钮
    • 13.9 自动播放
    • 13 JS完整代码
  • 14 bootstrapt轮播图

BOM

  1. 浏览器对象模型
  2. 把「浏览器」当做一个「对象」来看待
  3. BOM 的顶级对象是 window
  4. BOM 学习的是浏览器窗口交互的一些对象
  5. BOM 是浏览器厂商在各自浏览器上定义的,兼容性较差
  6. BOM 比 DOM 更大,它包含 DOM。

window 对象是浏览器的顶级对象,它具有双重角色。

  1. 它是 JS 访问浏览器窗口的一个接口。

  2. 它是一个全局对象。定义在全局作用域中的变量、函数都会变成 window 对象的属性和方法。

在调用的时候可以省略 window,前面学习的对话框都属于 window 对象方法,如 alert()、prompt() 等。

**注意:**window下的一个特殊属性 window.name

1 窗口加载事件

load

2 定时器

2.1 一次定时器

windows.setTimeOut([回调函数],[毫秒字符串])

**效果:**当毫秒倒计时结束,调用该函数

应用例子:

2.2 清除定时器

windows.clearTimeOut([一次定时器的ID(标识)])

**效果:**清除所有类型的定时器的效果

应用例子:

2.3 重复定时器

windows.interval([回调函数],[毫秒字符串])

**效果:**每隔一段时间调用该函数

**应用例子:**轮播图、秒杀倒计时

2.4 秒杀倒计时案例

1.页面空白问题:在打开浏览器的时候就调用一次静态倒计时

2.静态倒计时的实现

3.动态倒计时的实现

<!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>
        div {
            margin: 200px;
        }

        span {
            display: inline-block;
            width: 40px;
            height: 40px;
            background-color: #333;
            font-size: 20px;
            color: #fff;
            text-align: center;
            line-height: 40px;
        }
    </style>
</head>

<body>
    <div>
        <span class="hour">1</span>
        <span class="minute">2</span>
        <span class="second">3</span>
    </div>
    <script>
        // 1. 获取元素 
        var hour = document.querySelector('.hour'); // 小时的黑色盒子
        var minute = document.querySelector('.minute'); // 分钟的黑色盒子
        var second = document.querySelector('.second'); // 秒数的黑色盒子
        var inputTime = +new Date('2022-5-1 18:00:00'); // 返回的是用户输入时间总的毫秒数
        countDown(); // 我们先调用一次这个函数,防止第一次刷新页面有空白 
        // 2. 开启定时器
        setInterval(countDown, 1000);
		// 3 获取静态倒计时
        function countDown() {
            var nowTime = +new Date(); // 返回的是当前时间总的毫秒数
            var times = (inputTime - nowTime) / 1000; // times是剩余时间总的秒数 
            var h = parseInt(times / 60 / 60 % 24); //时
            h = h < 10 ? '0' + h : h;//进位
            hour.innerHTML = h; // 把剩余的小时给 小时黑色盒子
            var m = parseInt(times / 60 % 60); // 分
            m = m < 10 ? '0' + m : m;
            minute.innerHTML = m;
            var s = parseInt(times % 60); // 当前的秒
            s = s < 10 ? '0' + s : s;
            second.innerHTML = s;
        }
    </script>
</body>

</html

image-20220106195324501

2.5 发送短信案例

1.如何让按钮不可选以及恢复?

2.倒计时负数问题

<!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>
</head>

<body>
    手机号码: <input type="number"> <button>发送</button>
    <script>
        // 按钮点击之后,会禁用 disabled 为true 
        // 同时按钮里面的内容会变化, 注意 button 里面的内容通过 innerHTML修改
        // 里面秒数是有变化的,因此需要用到定时器
        // 定义一个变量,在定时器里面,不断递减
        // 如果变量为0 说明到了时间,我们需要停止定时器,并且复原按钮初始状态
        var btn = document.querySelector('button');
        var time = 3; // 定义剩下的秒数
        btn.addEventListener('click', function() {
            btn.disabled = true;
            var timer = setInterval(function() {
                if (time == 0) {
                    // 清除定时器和复原按钮
                    clearInterval(timer);
                    btn.disabled = false;
                    btn.innerHTML = '发送';
                } else {
                    btn.innerHTML = '还剩下' + time + '秒';
                    time--;
                }
            }, 1000);

        })
    </script>
</body>

</html>

image-20220106200327992

3 JS同步和异步

多个同步:

执行过程:按照编写顺序执行

同步和异步:

执行过程:当异步函数被调用时,位置转移到任务栈,当执行完同步任务,执行栈持续对任务栈监听,当异步区有函数时,转移异步函数回到执行栈执行。

多个异步:

执行过程:按照调用顺序执行

image-20220106201657506

4 location对象

4.1 对象属性

image-20220106202517714

**重点:**href 和 search

4.1.1 5秒后页面跳转案例

<!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>
</head>

<body>
    <button>点击</button>
    <div></div>
    <script>
        var btn = document.querySelector('button');
        var div = document.querySelector('div');
        btn.addEventListener('click', function() {
            // console.log(location.href);
            location.href = 'http://www.itcast.cn';
        })
        var timer = 5;
        setInterval(function() {
            if (timer == 0) {
                location.href = 'http://www.itcast.cn';
            } else {
                div.innerHTML = '您将在' + timer + '秒钟之后跳转到首页';
                timer--;
            }

        }, 1000);
    </script>
</body>

</html>

4.1.3 不同页面数据传递案例

步骤:

1 获取url参数

2 去掉参数中的问号:利用 substr(‘起始的位置’,截取几个字符);

3 获取参数中的属性值:利用 split() 分割为数组

4 获取该数组中的目标值

<!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>
</head>

<body>
    <div></div>
    <script>
        console.log(location.search); // ?uname=andy
        // 1.先去掉?  substr('起始的位置',截取几个字符);
        var params = location.search.substr(1); // uname=andy
        console.log(params);
        // 2. 利用=把字符串分割为数组 split('=');
        var arr = params.split('=');
        console.log(arr); // ["uname", "ANDY"]
        var div = document.querySelector('div');
        // 3.把数据写入div中
        div.innerHTML = arr[1] + '欢迎您';
    </script>
</body>

</html>

4.2 对象方法

image-20220106204740405

5 navigator对象

**内容:**navigator 对象包含有关浏览器的信息,它有很多属性,我们最常用的是 userAgent,该属性可以返回由客户机发送服务器的 user-agent 头部的值。

**应用案例:**下面前端代码可以判断用户那个终端打开页面,实现跳转

if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|
Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS
|Symbian|Windows Phone)/i))) {
 window.location.href = ""; //手机
} else {
 window.location.href = ""; //电脑
}

6 history对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zS3wEgnw-1671263277489)(D:\200The Project\TyporaProject01\pingJS_edu\JS.assets\image-20220106205250475.png)]

**应用场景:**history 对象一般在实际开发中比较少用,但是会在一些 OA 办公系统中见到:

image-20220106205310711

7 offset系列

功能:

  1. offset 翻译过来就是偏移量, 我们使用 offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
  2. 获得元素距离带有定位父元素的位置
  3. 获得元素自身的大小(宽度高度)

注意: 返回的数值都不带单位

7.1 属性

image-20220106210508564

7.2 offset和style 的区别

offset:

  1. offset 可以得到任意样式表中的样式值
  2. offset 系列获得的数值是没有单位的
  3. offsetWidth 包含padding+border+width
  4. offsetWidth 等属性是只读属性,只能获取不能赋值

**=>**所以,我们想要获取元素大小位置,用offset更合适

style:

  1. style 只能得到行内样式表中的样式值
  2. style.width 获得的是带有单位的字符串
  3. style.width 获得不包含padding和border 的值
  4. style.width 是可读写属性,可以获取也可以赋值

**=>**所以,我们想要给元素更改值,则需要用style改变

7.3 获取鼠标在盒子内的坐标案例

① 我们在盒子内点击,想要得到鼠标距离盒子左右的距离。

② 首先得到鼠标在页面中的坐标(e.pageX, e.pageY)

③ 其次得到盒子在页面中的距离 ( box.offsetLeft, box.offsetTop)

④ 用鼠标距离页面的坐标减去盒子在页面中的距离,得到 鼠标在盒子内的坐标

⑤ 如果想要移动一下鼠标,就要获取最新的坐标,使用鼠标移动事件 mousemove

var box = document.querySelector('.box');
box.addEventListener('mousemove', function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
this.innerHTML = 'x坐标是' + x + ' y坐标是' + y;
})

8 client系列

client 翻译过来就是客户端,我们使用 client 系列的相关属性来获取元素可视区的相关信息。通过 client 系列

的相关属性可以动态的得到该元素的边框大小、元素大小等。

8.1 属性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZN6qu15Y-1671263277490)(D:/200The Project/TyporaProject01/pingJS_edu/BOM.assets/image-20220106213141075.png)]

8.2 立即执行函数

语法: (function() {})() 相当于调用函数 或者 (function(){}()) 这个比较老

主要作用: 创建一个独立的作用域。 避免了命名冲突问题

9 scroll系列

9.1 概述

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

属性:

image-20220106213707412

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

image-20220106213736119

9.2 固定侧边栏案例

10 mouseenter鼠标事件

效果:

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

11 动画函数

11.1 动画实现原理

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

实现步骤:

  1. 获得盒子当前位置

  2. 让盒子在当前位置加上1个移动距离

  3. 利用定时器不断重复这个操作

  4. 加一个结束定时器的条件

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

应用案例:

<!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>
        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');
        var timer = setInterval(function() {
            if (div.offsetLeft >= 400) {
                // 停止动画 本质是停止定时器
                clearInterval(t
                              imer);
            }
            div.style.left = div.offsetLeft + 1 + 'px';
        }, 30);
    </script>
</body>

</html>

11.2 封装动画

**好处:**可以重复利用

<script>
        // 简单动画函数封装obj目标对象 target 目标位置
        function animate(obj, target) {
            var timer = setInterval(function() {
                if (obj.offsetLeft >= target) {
                    // 停止动画 本质是停止定时器
                    clearInterval(timer);
                }
                obj.style.left = obj.offsetLeft + 1 + 'px';

            }, 30);
        }

        var div = document.querySelector('div');
        var span = document.querySelector('span');
        // 调用函数
        animate(div, 300);
        animate(span, 200);
    </script>

11.3 不同元素记录不同的定时器案例

好处:

1.给不同的元素指定了不同的定时器

2.传入的是对象,不会因为重复定义变量而浪费空间

问题:

1.重复调用定时器函数的bug:先清除以前的定时器,只保留当前的一个定时器执行

<script>
        // var obj = {};
        // obj.name = 'andy';
        // 简单动画函数封装obj目标对象 target 目标位置
        // 给不同的元素指定了不同的定时器
        function animate(obj, target) {
            // 当我们不断的点击按钮,这个元素的速度会越来越快,因为开启了太多的定时器
            // 解决方案就是 让我们元素只有一个定时器执行
            // 先清除以前的定时器,只保留当前的一个定时器执行
            clearInterval(obj.timer);
            obj.timer = setInterval(function() {
                if (obj.offsetLeft >= target) {
                    // 停止动画 本质是停止定时器
                    clearInterval(obj.timer);
                }
                obj.style.left = obj.offsetLeft + 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>

12 缓动动画

12.1 缓动动画原理

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

实现思路:

  1. 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来。

  2. 核心算法: (目标值 - 现在的位置 ) / 10 做为每次移动的距离 步长

  3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器

  4. 注意步长值需要取整

12.2 基本代码实现

步骤细节:

步长值写到定时器里里面

步长公式:(目标值 - 现在的位置) / 10

<script>
        // 缓动动画函数封装obj目标对象 target 目标位置
        // 思路:
        // 1. 让盒子每次移动的距离慢慢变小, 速度就会慢慢落下来。
        // 2. 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长
        // 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
        function animate(obj, target) {
            // 先清除以前的定时器,只保留当前的一个定时器执行
            clearInterval(obj.timer);
            obj.timer = setInterval(function() {
                // 步长值写到定时器的里面
                var step = (target - obj.offsetLeft) / 10;
                if (obj.offsetLeft == target) {
                    // 停止动画 本质是停止定时器
                    clearInterval(obj.timer);
                }
                // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
                obj.style.left = obj.offsetLeft + step + 'px';

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

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

12.3 实现后退

问题解决:

1.运动位置带有小数,没有到指定位置:把步长值改为整数 不要出现小数:math.ceil()向前取整

2.后退功能没有到指定位置,带小数:步长向后取整Math.floor()

<script>
        // 缓动动画函数封装obj目标对象 target 目标位置
        // 思路:
        // 1. 让盒子每次移动的距离慢慢变小, 速度就会慢慢落下来。
        // 2. 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长
        // 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
        function animate(obj, target) {
            // 先清除以前的定时器,只保留当前的一个定时器执行
            clearInterval(obj.timer);
            obj.timer = setInterval(function() {
                // 步长值写到定时器的里面
                // 把我们步长值改为整数 不要出现小数的问题
                // var step = Math.ceil((target - obj.offsetLeft) / 10);
                var step = (target - obj.offsetLeft) / 10;
                step = step > 0 ? Math.ceil(step) : Math.floor(step);
                if (obj.offsetLeft == target) {
                    // 停止动画 本质是停止定时器
                    clearInterval(obj.timer);
                }
                // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
                obj.style.left = obj.offsetLeft + step + 'px';

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

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

12.4 回调函数

**效果:**当盒子移动结束,其颜色变化

<script>
        // 缓动动画函数封装obj目标对象 target 目标位置
        // 思路:
        // 1. 让盒子每次移动的距离慢慢变小, 速度就会慢慢落下来。
        // 2. 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长
        // 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
        function animate(obj, target, callback) {
            // console.log(callback);  callback = function() {}  调用的时候 callback()

            // 先清除以前的定时器,只保留当前的一个定时器执行
            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) {
                    // 停止动画 本质是停止定时器
                    clearInterval(obj.timer);
                    // 回调函数写到定时器结束里面
                    if (callback) {
                        // 调用函数
                        callback();
                    }
                }
                // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
                obj.style.left = obj.offsetLeft + step + 'px';

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

        btn500.addEventListener('click', function() {
            // 调用函数
            animate(span, 500);
        })
        btn800.addEventListener('click', function() {
                // 调用函数
                animate(span, 800, function() {
                    // alert('你好吗');
                    span.style.backgroundColor = 'red';
                });
            })
            // 匀速动画 就是 盒子是当前的位置 +  固定的值 10 
            // 缓动动画就是  盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10)
    </script>

12.5 侧边栏弹出弹入案例

知识点:

1 封装动画函数到文件

代码实现:

在html

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .sliderbar {
            position: fixed;
            right: 0;
            bottom: 100px;
            width: 40px;
            height: 40px;
            text-align: center;
            line-height: 40px;
            cursor: pointer;
            color: #fff;
        }
        
        .con {
            position: absolute;
            left: 0;
            top: 0;
            width: 200px;
            height: 40px;
            background-color: purple;
            z-index: -1;
        }
    </style>
    <script src="animate.js"></script>
</head>

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

    <script>
        // 1. 获取元素
        var sliderbar = document.querySelector('.sliderbar');
        var con = document.querySelector('.con');
        // 当我们鼠标经过 sliderbar 就会让 con这个盒子滑动到左侧
        // 当我们鼠标离开 sliderbar 就会让 con这个盒子滑动到右侧
        sliderbar.addEventListener('mouseenter', function() {
            // animate(obj, target, callback);
            animate(con, -160, function() {
                // 当我们动画执行完毕,就把 ← 改为 →
                sliderbar.children[0].innerHTML = '→';
            });

        })
        sliderbar.addEventListener('mouseleave', function() {
            // animate(obj, target, callback);
            animate(con, 0, function() {
                sliderbar.children[0].innerHTML = '←';
            });

        })
    </script>
</body>

</html>

在animate.js

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

    // 先清除以前的定时器,只保留当前的一个定时器执行
    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) {
            // 停止动画 本质是停止定时器
            clearInterval(obj.timer);
            // 回调函数写到定时器结束里面
            // if (callback) {
            //     // 调用函数
            //     callback();
            // }
            callback && callback();
        }
        // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
        obj.style.left = obj.offsetLeft + step + 'px';

    }, 15);
}

13 网页轮播图

13.1 功能需求

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

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

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

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

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

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

13.2 基本环境

实现思路:让 ul 包含轮播图 li,水平显示(让ul足够大且添加浮动),再利用隐藏的样式

<div class="focus fl">
    <!-- 左侧按钮 -->
    <a href="javascript:;" class="arrow-l">
        &lt;
    </a>
    <!-- 右侧按钮 -->
    <a href="javascript:;" class="arrow-r"></a>
    <!-- 核心的滚动区域 -->
    <ul>
        <li>
            <a href="#"><img src="upload/focus.jpg" alt=""></a>
        </li>
        <li>
            <a href="#"><img src="upload/focus1.jpg" alt=""></a>
        </li>
        <li>
            <a href="#"><img src="upload/focus2.jpg" alt=""></a>
        </li>
        <li>
            <a href="#"><img src="upload/focus3.jpg" alt=""></a>
        </li>
    </ul>
    <!-- 小圆圈 -->
    <ol class="circle">

    </ol>
</div>
.focus {
    position: relative;
    width: 721px;
    height: 455px;
    background-color: purple;
    overflow: hidden;
}

.focus ul {
    position: absolute;
    top: 0;
    left: 0;
    width: 600%;
}

.focus ul li {
    float: left;
}

13.3 鼠标悬浮与离开

① 因为js较多,我们单独新建js文件夹,再新建js文件, 引入页面中。

② 此时需要添加 load 事件。

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

④ 显示隐藏 display 按钮。

13.4 动态小圆圈

① 动态生成小圆圈

② 核心思路:小圆圈的个数要跟图片张数一致

③ 所以首先先得到ul里面图片的张数(图片放入li里面,所以就是li的个数)

④ 利用循环动态生成小圆圈(这个小圆圈要放入ol里面)

⑤ 创建节点 createElement(‘li’)

⑥ 插入节点 ol. appendChild(li)

⑦ 第一个小圆圈需要添加 current 类

知识点:

节点查询、插入、创建、添加类名

① 小圆圈的排他思想

② 点击当前小圆圈,就添加current类

③ 其余的小圆圈就移除这个current类

④ 注意: 我们在刚才生成小圆圈的同时,就可以直接绑定这个点击事件了。

① 点击小圆圈滚动图片

② 此时用到animate动画函数,将js文件引入(注意,因为index.js 依赖 animate.js 所以,animate.js 要写到 index.js 上面)

③ 使用动画函数的前提,该元素必须有定位

④ 注意是ul 移动 而不是小li

⑤ 滚动图片的核心算法: 点击某个小圆圈 , 就让图片滚动 小圆圈的索引号乘以图片的宽度做为ul移动距离

⑥ 此时需要知道小圆圈的索引号, 我们可以在生成小圆圈的时候,给它设置一个自定义属性,点击的时候获取这个自定

义属性即可。

知识点:

1 获取当前点击的li

2 添加绝对定位

3 移动距离算法

	// 3. 动态生成小圆圈  有几张图片,我就生成几个小圆圈
    var ul = focus.querySelector('ul');
    var ol = focus.querySelector('.circle');
    // console.log(ul.children.length);
    for (var i = 0; i < ul.children.length; i++) {
        // 创建一个小li 
        var li = document.createElement('li');
        // 记录当前小圆圈的索引号 通过自定义属性来做 
        li.setAttribute('index', i);
        // 把小li插入到ol 里面
        ol.appendChild(li);
        // 4. 小圆圈的排他思想 我们可以直接在生成小圆圈的同时直接绑定点击事件
        li.addEventListener('click', function() {
            // 干掉所有人 把所有的小li 清除 current 类名
            for (var i = 0; i < ol.children.length; i++) {
                ol.children[i].className = '';
            }
            // 留下我自己  当前的小li 设置current 类名
            this.className = 'current';
            // 5. 点击小圆圈,移动图片 当然移动的是 ul 
            // ul 的移动距离 小圆圈的索引号 乘以 图片的宽度 注意是负值
            // 当我们点击了某个小li 就拿到当前小li 的索引号
            var index = this.getAttribute('index');
            // 当我们点击了某个小li 就要把这个li 的索引号给 num  
            num = index;
            // 当我们点击了某个小li 就要把这个li 的索引号给 circle  
            circle = index;
            // num = circle = index;
            console.log(focusWidth);
            console.log(index);

            animate(ul, -index * focusWidth);
        })
    }

13.5 右侧按钮

① 点击右侧按钮一次,就让图片滚动一张。

② 声明一个变量num, 点击一次,自增1, 让这个变量乘以图片宽度,就是 ul 的滚动距离。

③ 图片无缝滚动原理

④ 把ul 第一个li 复制一份,放到ul 的最后面

⑤ 当图片滚动到克隆的最后一张图片时, 让ul 快速的、不做动画的跳到最左侧: left 为0

⑥ 同时num 赋值为0,可以从新开始滚动图片了

	// 6. 克隆第一张图片(li)放到ul 最后面
    var first = ul.children[0].cloneNode(true);
    ul.appendChild(first);
    // 7. 点击右侧按钮, 图片滚动一张
    var num = 0;
    // circle 控制小圆圈的播放
    var circle = 0;
    // flag 节流阀
    var flag = true;
    arrow_r.addEventListener('click', function() {
        if (flag) {
            flag = false; // 关闭节流阀
            // 如果走到了最后复制的一张图片,此时 我们的ul 要快速复原 left 改为 0
            if (num == ul.children.length - 1) {
                ul.style.left = 0;
                num = 0;
            }
            num++;
            animate(ul, -num * focusWidth, function() {
                flag = true; // 打开节流阀
            });
            // 8. 点击右侧按钮,小圆圈跟随一起变化 可以再声明一个变量控制小圆圈的播放
            circle++;
            // 如果circle == 4 说明走到最后我们克隆的这张图片了 我们就复原
            if (circle == ol.children.length) {
                circle = 0;
            }
            // 调用函数
            circleChange();
        }
    });

13.6 克隆第一张图片

① 克隆第一张图片

② 克隆ul 第一个li cloneNode() 加true 深克隆 复制里面的子节点 false 浅克隆

③ 添加到 ul 最后面 appendChild

    var first = ul.children[0].cloneNode(true);

13.7 小圆圈跟随

 // 7. 点击右侧按钮, 图片滚动一张
    var num = 0;
    // circle 控制小圆圈的播放
    var circle = 0;
    // flag 节流阀
    var flag = true;
    arrow_r.addEventListener('click', function() {
        if (flag) {
            flag = false; // 关闭节流阀
            // 如果走到了最后复制的一张图片,此时 我们的ul 要快速复原 left 改为 0
            if (num == ul.children.length - 1) {
                ul.style.left = 0;
                num = 0;
            }
            num++;
            animate(ul, -num * focusWidth, function() {
                flag = true; // 打开节流阀
            });
            // 8. 点击右侧按钮,小圆圈跟随一起变化 可以再声明一个变量控制小圆圈的播放
            circle++;
            // 如果circle == 4 说明走到最后我们克隆的这张图片了 我们就复原
            if (circle == ol.children.length) {
                circle = 0;
            }
            // 调用函数
            circleChange();
        }
    });

**注意两个bug:**小圆圈和按钮的互相同步

// 当我们点击了某个小li 就拿到当前小li 的索引号
var index = this.getAttribute('index');
// 当我们点击了某个小li 就要把这个li 的索引号给 num  
num = index;
// 当我们点击了某个小li 就要把这个li 的索引号给 circle  
circle = index;

13.8 左侧按钮

① 点击右侧按钮, 小圆圈跟随变化

② 最简单的做法是再声明一个变量circle,每次点击自增1,注意,左侧按钮也需要这个变量,因此要声明全局变量。

③ 但是图片有5张,我们小圆圈只有4个少一个,必须加一个判断条件

④ 如果circle == 4 就 从新复原为 0

13.9 自动播放

① 自动播放功能

② 添加一个定时器

③ 自动播放轮播图,实际就类似于点击了右侧按钮

④ 此时我们使用手动调用右侧按钮点击事件 arrow_r.click()

⑤ 鼠标经过focus 就停止定时器

⑥ 鼠标离开focus 就开启定时器

	// 10. 自动播放轮播图
    var timer = setInterval(function() {
        //手动调用点击事件
        arrow_r.click();
    }, 2000);

13 JS完整代码

window.addEventListener('load', function() {
    // 1. 获取元素
    var arrow_l = document.querySelector('.arrow-l');
    var arrow_r = document.querySelector('.arrow-r');
    var focus = document.querySelector('.focus');
    var focusWidth = focus.offsetWidth;
    // 2. 鼠标经过focus 就显示隐藏左右按钮
    focus.addEventListener('mouseenter', function() {
        arrow_l.style.display = 'block';
        arrow_r.style.display = 'block';
        clearInterval(timer);
        timer = null; // 清除定时器变量
    });
    focus.addEventListener('mouseleave', function() {
        arrow_l.style.display = 'none';
        arrow_r.style.display = 'none';
        timer = setInterval(function() {
            //手动调用点击事件
            arrow_r.click();
        }, 2000);
    });
    // 3. 动态生成小圆圈  有几张图片,我就生成几个小圆圈
    var ul = focus.querySelector('ul');
    var ol = focus.querySelector('.circle');
    // console.log(ul.children.length);
    for (var i = 0; i < ul.children.length; i++) {
        // 创建一个小li 
        var li = document.createElement('li');
        // 记录当前小圆圈的索引号 通过自定义属性来做 
        li.setAttribute('index', i);
        // 把小li插入到ol 里面
        ol.appendChild(li);
        // 4. 小圆圈的排他思想 我们可以直接在生成小圆圈的同时直接绑定点击事件
        li.addEventListener('click', function() {
            // 干掉所有人 把所有的小li 清除 current 类名
            for (var i = 0; i < ol.children.length; i++) {
                ol.children[i].className = '';
            }
            // 留下我自己  当前的小li 设置current 类名
            this.className = 'current';
            // 5. 点击小圆圈,移动图片 当然移动的是 ul 
            // ul 的移动距离 小圆圈的索引号 乘以 图片的宽度 注意是负值
            // 当我们点击了某个小li 就拿到当前小li 的索引号
            var index = this.getAttribute('index');
            // 当我们点击了某个小li 就要把这个li 的索引号给 num  
            num = index;
            // 当我们点击了某个小li 就要把这个li 的索引号给 circle  
            circle = index;
            // num = circle = index;
            console.log(focusWidth);
            console.log(index);

            animate(ul, -index * focusWidth);
        })
    }
    // 把ol里面的第一个小li设置类名为 current
    ol.children[0].className = 'current';
    // 6. 克隆第一张图片(li)放到ul 最后面
    var first = ul.children[0].cloneNode(true);
    ul.appendChild(first);
    // 7. 点击右侧按钮, 图片滚动一张
    var num = 0;
    // circle 控制小圆圈的播放
    var circle = 0;
    // flag 节流阀
    var flag = true;
    arrow_r.addEventListener('click', function() {
        if (flag) {
            flag = false; // 关闭节流阀
            // 如果走到了最后复制的一张图片,此时 我们的ul 要快速复原 left 改为 0
            if (num == ul.children.length - 1) {
                ul.style.left = 0;
                num = 0;
            }
            num++;
            animate(ul, -num * focusWidth, function() {
                flag = true; // 打开节流阀
            });
            // 8. 点击右侧按钮,小圆圈跟随一起变化 可以再声明一个变量控制小圆圈的播放
            circle++;
            // 如果circle == 4 说明走到最后我们克隆的这张图片了 我们就复原
            if (circle == ol.children.length) {
                circle = 0;
            }
            // 调用函数
            circleChange();
        }
    });

    // 9. 左侧按钮做法
    arrow_l.addEventListener('click', function() {
        if (flag) {
            flag = false;
            if (num == 0) {
                num = ul.children.length - 1;
                ul.style.left = -num * focusWidth + 'px';

            }
            num--;
            animate(ul, -num * focusWidth, function() {
                flag = true;
            });
            // 点击左侧按钮,小圆圈跟随一起变化 可以再声明一个变量控制小圆圈的播放
            circle--;
            // 如果circle < 0  说明第一张图片,则小圆圈要改为第4个小圆圈(3)
            // if (circle < 0) {
            //     circle = ol.children.length - 1;
            // }
            circle = circle < 0 ? ol.children.length - 1 : circle;
            // 调用函数
            circleChange();
        }
    });

    function circleChange() {
        // 先清除其余小圆圈的current类名
        for (var i = 0; i < ol.children.length; i++) {
            ol.children[i].className = '';
        }
        // 留下当前的小圆圈的current类名
        ol.children[circle].className = 'current';
    }
    // 10. 自动播放轮播图
    var timer = setInterval(function() {
        //手动调用点击事件
        arrow_r.click();
    }, 2000);

})

14 bootstrapt轮播图

Bootstrap 是一个简洁、直观、强悍的前端开发框架,它让 web 开发更迅速、简单。

它能开发PC端,也能开发移动端

Bootstrap JS插件使用步骤:

  1. 引入相关js 文件

  2. 复制HTML 结构

  3. 修改对应样式

  4. 修改相应JS 参数

轮播图实现案例完整代码:

<!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>
    <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
    <script src="bootstrap/js/jquery.min.js"></script>
    <script src="bootstrap/js/bootstrap.min.js"></script>
    <style>
        .focus {
            width: 800px;
            height: 300px;
            background-color: pink;
            margin: 100px auto;
        }
        
        .carousel,
        .carousel img {
            width: 100%;
            height: 300px!important;
        }
    </style>
</head>

<body>
    <div class="focus">
        <div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
            <!-- Indicators 小圆点 -->
            <ol class="carousel-indicators">
                <li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li>
                <li data-target="#carousel-example-generic" data-slide-to="1"></li>
                <li data-target="#carousel-example-generic" data-slide-to="2"></li>
            </ol>

            <!-- Wrapper for slides 轮播图片 -->
            <div class="carousel-inner" role="listbox">
                <div class="item active">
                    <img src="upload/banner.dpg" alt="...">
                    <div class="carousel-caption">
                        这是我的图片1
                    </div>
                </div>
                <div class="item">
                    <img src="upload/banner1.dpg" alt="...">
                    <div class="carousel-caption">
                        这是我的图片2
                    </div>
                </div>
                <div class="item">
                    <img src="upload/banner2.dpg" alt="...">
                    <div class="carousel-caption">
                        这是我的图片3
                    </div>
                </div>
                ...
            </div>

            <!-- Controls 左右箭头 -->
            <a class="left carousel-control" href="#carousel-example-generic" role="button" data-slide="prev">
                <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
                <span class="sr-only">Previous</span>
            </a>
            <a class="right carousel-control" href="#carousel-example-generic" role="button" data-slide="next">
                <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
                <span class="sr-only">Next</span>
            </a>
        </div>
    </div>
    <script>
        $('.carousel').carousel({
            interval: 2000
        })
    </script>
</body>

</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/97280.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于缓存与数据双写一致性问题(清晰易懂)

缓存与数据双写一致性问题 一般来说&#xff0c;执行更新操作时&#xff0c;我们会有两种选择&#xff1a; 先操作数据库&#xff0c;再操作缓存先操作缓存&#xff0c;再操作数据库 这两个操作要么同时成功&#xff0c;要么同时失败。所以&#xff0c;这会演变成一个分布式…

架构设计(五):有状态服务和无状态服务

架构设计&#xff08;五&#xff09;&#xff1a;有状态服务和无状态服务 作者&#xff1a;Grey 原文地址&#xff1a; 博客园&#xff1a;架构设计&#xff08;五&#xff09;&#xff1a;有状态服务和无状态服务 CSDN&#xff1a;架构设计&#xff08;五&#xff09;&…

批量查询搜狗收录,查询结果不准是什么原因

网站的收录情况是常用的技术手段&#xff0c;会影响到网站的流量和展现量&#xff0c;想要获得一个好的收录就必须重视原创内容&#xff0c;因为网站的收录直接影响力搜索引擎的关键词排名。 网站收录信息如何批量查询? 以搜狗收录为例&#xff1a; 1、打开SEO综合…

17 CPP面向对象编程

简单实用类&#xff1a; 1 类的成员函数可以直接访问该类其它的成员函数 2 类的成员函数可以重载。 3 类指针的用法与结构体指针用法相同 4 类的成员可以是任意数据类型&#xff08;类中也可以有枚举&#xff09; 5 可以为类的成员指定缺省值&#xff08;C11标准&#xff…

Redis基础数据结构源码

1、SDS&#xff1a;动态字符串 src/sds.h:50 struct sdshdr {// 记录buf数组中已使用的字节数&#xff0c;即SDS字符串长度int len;// 记录buf数组中未使用的字节数int free;// 字节数组&#xff0c;用于保存字符串char buf[]; } 杜绝缓冲区溢出。减少修改字符串长度时所需的内…

概率统计·参数估计【区间估计】

置信区间 求解步骤 例 构造一个函数&#xff08;主要是函数不用依赖未知量只有一个未知量&#xff0c;问μ的置信水平用这个函数&#xff0c;如果σ也未知&#xff0c;就要替换掉这个式子中的σ为S&#xff0c;并且变成服从 t 分布&#xff09;取上下区间&#xff08;用2个常数…

邪道方法-字典转字符串以传参字典给多GPU训练的mmseg

文章首发及后续更新&#xff1a;https://mwhls.top/4387.html&#xff0c;无图/无目录/格式错误/更多相关请至首发页查看。 新的更新内容请到mwhls.top查看。 欢迎提出任何疑问及批评&#xff0c;非常感谢&#xff01; 目录引言 解决方法 引言 我想把字典传参给多GPU训练&#…

CleanMyMac X4.12.2版本功能实用性测评

相信大多数MAC用户都较为了解&#xff0c;Mac虽然有着许多亮点的性能&#xff0c;但是让用户叫苦不迭的还其硬盘空间小的特色&#xff0c;至于很多人因为文件堆积以及软件缓存等&#xff0c;造成系统空间内存不够使用的情况。于是清理工具就成为了大多数MAC用户使用频率较高的实…

他不知道他病了

没时间读书&#xff0c;关注我每天更新一本好书关于作者关于本书核心内容一、如何理解缺乏病识感二、沟通四步策略1.倾听2.同理心3.赞同4.结为伙伴三、如果仍然不接受治疗&#xff0c;怎么办金句关于作者 泽维尔阿玛多是纽约市哥伦比亚大学心理学副教授&#xff0c;全美精神障…

javaSE - StringBuffer 和 StringBuilder(字符串拼接)

前言 StringBuffer 、 StringBuilder、 String 是三种数据类型 首先来回顾下String类的特点&#xff1a; 任何的字符串常量都是String对象&#xff0c;而且String的常量一旦声明不可改变&#xff0c;如果改变对象内容&#xff0c;改变的是其引用的指向而已。通常来讲String的…

Oracle-expdp导出时间变长问题分析

前言: 近期处理了一起expdp导出时间变长的问题&#xff0c;在数据量没有较大增长的情况下&#xff0c;expdp导出时间发生倍数增长&#xff0c;后面分析发现是由于Bug 27634991导致在AMM,ASMM模式下&#xff0c;由于streams pool内存抖动触发了内存收缩&#xff0c;内存收缩的过…

jsp+ssm计算机毕业设计窗户管理系统【附源码】

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JSPSSM mybatis Maven等等组成&#xff0c;B/S模式 Mave…

[附源码]Nodejs计算机毕业设计基于社区人员管理系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

【图像去噪】DCT图像去噪【含GUI Matlab源码 614期】

⛄一、图像去噪及滤波简介 1 图像去噪 1.1 图像噪声定义 噪声是干扰图像视觉效果的重要因素&#xff0c;图像去噪是指减少图像中噪声的过程。噪声分类有三种&#xff1a;加性噪声&#xff0c;乘性噪声和量化噪声。我们用f(x,y&#xff09;表示图像&#xff0c;g(x,y&#xff0…

基于java+springmvc+mybatis+vue+mysql的戒烟网站

项目介绍 大量研究证据表明&#xff0c;戒烟可降低或消除吸烟导致的健康危害。任何人在任何年龄戒烟均可获益&#xff0c;且戒烟越早、持续时间越长&#xff0c;健康获益就越大。随着时代发展人们对健康也越来越重视&#xff0c;更多的人参与到了戒烟的行列中来&#xff0c;本…

[go]分布式系统之snowflake与锁

文章目录分布式id生成器分布式锁负载均衡go语言在网络服务模块有着得天独厚的优势&#xff1b; https://www.cnblogs.com/thepoy/p/14573822.html中详细介绍了涉及到的分布式相关技术。分布式id生成器 Snowflake&#xff08;雪花算法&#xff09;&#xff0c;由Twitter提出并开…

六问 Kafka 为啥那么牛

1 Kafka 简介 1.1 Kafka 概述 Kafka 是一个分布式的基于发布/订阅模式的消息队列&#xff0c;依靠其强悍的吞吐量&#xff0c;Kafka 主要应用于大数据实时处理领域。在数据采集、传输、存储的过程中发挥着举足轻重的作用。 Apache Kafka 由 Scala 写成&#xff0c;是由Apache软…

转行IT行业学什么比较好?月薪过万要多久?

学什么&#xff0c;比穿什么衣服的问题更难&#xff0c;因为职业的背后&#xff0c;更多的是抉择而不是选择&#xff0c;选错一件衣服可以重来&#xff0c;而选错一个职业所面对的结果&#xff0c;是非常让人痛苦的。 本文是小编对想转行IT行业的你最真挚的建议。 任何事情&a…

QT5.14.2搭建Android开发环境

项目需求:因项目需求需要使用QT开发功能类似的一个跨平台项目&#xff0c;基于Android系统上运行单机软件。 开发环境&#xff1a;Windows 10 QT5.14.2 搭建步骤&#xff1a; 1、安装Java软件&#xff0c;配置环境变量 java软件安装可以选择默认安装位置&#xff0c;我下载…

KNN学习

学习B站 【什么是KNN&#xff08;K近邻算法&#xff09;&#xff1f;【知多少】】 https://www.bilibili.com/video/BV1Ma411F7Y4/?share_sourcecopy_web&vd_sourced928ac2eb2c6b562d9488d15f78dfbf4 什么是KNN NN neural network 并不是 KNN 是k-Nearest Neighbors K 近…