DOM 获取元素

xmind

了解 DOM 的结构并掌握其基本的操作,体验 DOM 的在开发中的作用

Web API 基本认知

  1. 知道 ECMAScript 与 JavaScript 的关系,Web APIs 是浏览器扩展的功能。
  2. Web API 阶段我们学习那两部分?
    • DOM
    • BOM
  3. DOM 是什么?有什么作用?
    • DOM 是 文档对象模型
    • 操作网页内容,可以开发网页内容特效和实现用户交互
  4. DOM 树是什么?
    • 将 HTML 文档以树状结构直观的表现出来,我们称之为文档树DOM 树
    • 作用:文档树直观的体现了标签与标签之间的关系
  5. DOM 对象怎么创建的?
    • 浏览器根据 html 标签生成的 JS 对象(DOM 对象)
    • DOM 的核心就是把内容当 对象 来处理
  6. document 是什么?
    • 是 DOM 里提供的一个 对象
    • 网页所有内容都在 document 里面

严格意义上讲,我们在 JavaScript 阶段学习的知识绝大部分属于 ECMAScript 的知识体系,ECMAScript 简称 ES 它提供了一套语言标准规范,如变量、数据类型、表达式、语句、函数等语法规则都是由 ECMAScript 规定的。浏览器将 ECMAScript 大部分的规范加以实现,并且在此基础上又扩展一些实用的功能,这些被扩展出来的内容我们称为 Web APIs。

ECMAScript 运行在浏览器中然后再结合 Web APIs 才是真正的 JavaScript,Web APIs 的核心是 DOM 和 BOM。

JavaScript 历史扩展阅读

ECMAScript

JavaScript

Node.js

JavaScript 和 Node.js

Node.js 就是运行在服务端(后端)的 JavaScript。Node.js 是一个异步的(非阻塞 I/O)事件驱动的 JavaScript 的运行环境。

JavaScript 和 Node.js

Web APIs

JS 的组成

web-apis-intro

JS 基础阶段以及 Web APIs 阶段

JS 基础学习 ECMAScript 基础语法为后面作铺垫,Web APIs 是 JS 的应用,大量使用 JS 基础语法做交互效果

API 和 Web API

web 浏览器的重要部分

web 浏览器的软件中有很多活动的程序片段,而许多片段 web 开发人员无法使用 JavaScript 来控制或操作,因此 Web 浏览器是一个很复杂的软件组合。你可能认为这样的限制是不是好事,但是浏览器被锁定是有充分理由的,主要集中在安全方面。如果一个网站可以访问您存储的密码或其他敏感信息,犹如你一样登录到网站,试想会发生什么?

尽管有局限性,Web API 仍然允许我们访问许多的功能,使我们用 web 页做很多事情。有几个在代码中经常引用的非常明显的部位 - 下面的图表表示了直接出现在 web 页面视图中的浏览器的主要部分:

img

文档对象模型 DOM

文档对象模型 (DOM) 将 web 页面与到脚本或编程语言连接起来。通常是指 JavaScript,但将 HTML、SVG 或 XML 文档建模为对象并不是 JavaScript 语言的一部分。DOM 模型用一个逻辑树来表示一个文档,树的每个分支的终点都是一个节点 (node),每个节点都包含着对象 (objects)。DOM 的方法 (methods) 让你可以用特定方式操作这个树,用这些方法你可以改变文档的结构、样式或者内容。节点可以关联上事件处理器,一旦某一事件被触发了,那些事件处理器就会被执行。

这里还有一篇关于 DOM 的 介绍

DOM(Document Object Model)是将整个 HTML 文档的每一个标签元素视为一个对象,这个对象下包含了许多的属性和方法,通过操作这些属性或者调用这些方法实现对 HTML 的动态更新,为实现网页特效以及用户交互提供技术支撑。

在浏览器标签中当前载入的文档用文档对象模型来表示。这是一个由浏览器生成的 "树结构",使编程语言可以很容易的访问 HTML 结构 — 例如浏览器自己在呈现页面时,使用它将样式和其他信息应用于正确的元素,而页面呈现完成以后,开发人员可以用 JavaScript 操作 DOM。

简言之 DOM 是用来动态修改 HTML 的 (浏览器提供的一套专门用来 操作网页内容 的功能),其目的是开发网页特效及用户交互

DOM 树

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>标题</title>
  </head>
  <body>
    文本
    <a href="">链接名</a>
    <div id="" class="">文本</div>
  </body>
</html>

如下图所示,将 HTML 文档以树状结构直观的表现出来,我们称之为文档树或 DOM 树,文档树直观的体现了标签与标签之间的关系。

dom

DOM 节点

dom-object

节点是文档树的组成部分,每一个节点都是一个 DOM 对象,主要分为元素节点、属性节点、文本节点等。

document 对象

document 是 JavaScript 内置的专门用于 DOM 的对象,该对象包含了若干的属性和方法,document 是学习 DOM 的核心。

// document 是内置的对象
// console.log(typeof document);

// 1. 通过 document 获取根节点
console.log(document.documentElement); // 对应 html 标签

// 2. 通过 document 节取 body 节点
console.log(document.body); // 对应 body 标签

// 3. 通过 document.write 方法向网页输出内容
document.write("Hello World!");

上述列举了 document 对象的部分属性和方法,我们先对 document 有一个整体的认识。

获取 DOM 对象

查找元素 DOM 元素就是利用 JS 选择页面中标签元素。

  1. 获取一个 DOM 元素我们使用谁?能直接操作修改吗?
    • querySelector()
    • 可以
  2. 获取多个 DOM 元素我们使用谁?能直接修改吗?如果不能可以怎么做到修改?
    • querySelectorAll()
    • 不可以,只能通过遍历的方式一次给里面的元素做修改
  3. 获取页面中的标签我们最终常用那两种方式?
    • querySelectorAll()
    • querySelector()
  4. 他们两者的区别是什么?
    • querySelector() 只能选择一个元素,可以直接操作
    • querySelectorAll() 可以选择多个元素,得到的是伪数组,需要遍历得到每一个元素
  5. 他们两者小括号里面的参数有神马注意事项?
    • 里面写 css 选择器
    • 必须是字符串,也就是必须加引号

总结:

Document.querySelector()

文档

文档对象模型 Document 引用的 querySelector() 方法返回文档中与指定选择器或选择器组匹配的第一个 Element 对象。如果找不到匹配项,则返回 null

备注

匹配是使用深度优先先序遍历,从文档标记中的第一个元素开始,并按子节点的顺序依次遍历。

element = document.querySelector(selectors);

// selectors 包含一个或多个要匹配的选择器的 DOM 字符串 DOMString。该字符串必须是有效的 CSS 选择器字符串;如果不是,则引发 SYNTAX_ERR 异常。请参阅使用选择器定位 DOM 元素以获取有关选择器以及如何管理它们的更多信息。

// 返回值 表示文档中与指定的一组 CSS 选择器匹配的第一个元素,一个 Element 对象。如果没有匹配到,则返回 null。

// 如果您需要与指定选择器匹配的所有元素的列表,则应该使用 querySelectorAll() 。

// 异常 SYNTAX_ERR 指定 selectors 的语法无效。
备注

如果要匹配的 ID 或选择器不符合 CSS 语法(比如不恰当地使用了冒号或者空格),你必须用反斜杠将这些字符转义。由于 JavaScript 中,反斜杠是转义字符,所以当你输入一个文本串时,你必须将它转义两次(一次是为 JavaScript 字符串转义,另一次是为 querySelector 转义):

<div id="foo\bar"></div>
<div id="foo:bar"></div>
<script>
  console.log("#foo\bar"); // "#fooar"
  document.querySelector("#foo\bar"); // 不匹配任何元素

  console.log("#foo\\bar"); // "#foo\bar"
  console.log("#foo\\\\bar"); // "#foo\\bar"
  document.querySelector("#foo\\\\bar"); // 匹配第一个 div

  document.querySelector("#foo:bar"); // 不匹配任何元素
  document.querySelector("#foo\\:bar"); // 匹配第二个 div
</script>

Document.querySelectorAll()

Document.querySelectorAll - Web API 接口参考 | MDN (mozilla.org)

返回与指定的选择器组匹配的文档中的元素列表 (使用深度优先的先序遍历文档的节点)。返回的对象是 NodeList

NodeList

NodeList - Web API 接口参考 | MDN (mozilla.org)

NodeList (伪数组)对象是节点的集合,通常是由属性,如 Node.childNodes 和 方法,如 document.querySelectorAll 返回的。

  • 有长度有索引号的数组
  • 但是没有 pop() push() 等数组方法
  • 想要得到里面的每一个对象,则需要遍历(for)的方式获得。

NodeList 不是一个数组,是一个类似数组的对象 (Like Array Object)。虽然 NodeList 不是一个数组,但是可以使用 forEach() 来迭代。你还可以使用 Array.from() 将其转换为数组。

不过,有些浏览器较为过时,没有实现 NodeList.forEach()Array.from()。你可以用 Array.prototype.forEach() 来规避这一问题

elementList = parentNode.querySelectorAll(selectors);

// selectors 一个 DOMString 包含一个或多个匹配的选择器。这个字符串必须是一个合法的 CSS selector 如果不是,会抛出一个 SyntaxError 错误。有关使用选择器标识元素的更多信息,请参阅 Locating DOM elements using selectors 可以通过使用逗号分隔多个选择器来指定它们。

// 返回值 一个静态 NodeList,包含一个与至少一个指定选择器匹配的元素的 Element 对象,或者在没有匹配的情况下为空 NodeList

// SyntaxError 如果指定的 选择器 不合法,会抛出错误。如$("##div")
注意

  • 哪怕只有一个元素,通过 querySelectAll() 获取过来的也是一个伪数组,里面只有一个元素而已

  • 默认情况下,querySelectorAll() 仅验证选择器中的最后一个元素是否在搜索范围内。

    <div class="outer">
      <div class="select">
        <div class="inner"></div>
      </div>
    </div>
    
    <script>
      var select = document.querySelector(".select");
      var inner = select.querySelectorAll(".outer .inner");
      inner.length; // 1, not 0!
    </script>
    

    在这个例子中,当在 <div> 上下文中选择带有 "select" 类的 ".outer .inner" 时,仍然会找到类 ".inner" 的元素,即使 .outer 不是基类的后代 执行搜索的元素(".select")。

    :scope 伪类符合预期的行为,只匹配基本元素后代的选择器:

    var select = document.querySelector(".select");
    var inner = select.querySelectorAll(":scope .outer .inner");
    inner.length; // 0
    

Document.getElementById()

document.getElementById - Web API 接口参考 | MDN (mozilla.org)

Document 的方法 getElementById() 返回一个匹配特定 ID 的元素。由于元素的 ID 在大部分情况下要求是独一无二的,这个方法自然而然地成为了一个高效查找特定元素的方法。

如果需要查找到那些没有 ID 的元素,你可以考虑通过 CSS 选择器使用 querySelector()

var element = document.getElementById(id);

// element 是一个 Element 对象。如果当前文档中拥有特定 ID 的元素不存在则返回 null。
// id 是大小写敏感的字符串,代表了所要查找的元素的唯一 ID。
// 返回值 返回一个匹配到 ID 的 DOM Element 对象。若在当前 Document 下没有找到,则返回 null。
<!-- 点击颜色按钮给文字设置颜色 -->

<p id="para">Some text here</p>
<button onclick="changeColor('blue');">blue</button>
<button onclick="changeColor('red');">red</button>

<script>
  function changeColor(newColor) {
    var elem = document.getElementById("para");
    elem.style.color = newColor;
  }
</script>

Document.getElementsByTagName()

Document.getElementsByTagName() - Web API 接口参考 | MDN (mozilla.org)

返回一个包括所有给定标签名称的元素的 HTML 集合 HTMLCollection。整个文件结构都会被搜索,包括根节点。返回的 HTML 集合 是动态的,意味着它可以自动更新自己来保持和 DOM 树的同步而不用再次调用 document.getElementsByTagName()

var elements = document.getElementsByTagName(name);

// elements 是一个由发现的元素出现在树中的顺序构成的动态的 HTML 集合 HTMLCollection (但是看下面的提示) 。
// name 是一个代表元素的名称的字符串。特殊字符 "*" 代表了所有元素。

操作元素内容

  1. 设置/修改 DOM 元素内容有哪 2 种方式?
    • 元素.innerText 属性
    • 元素.innerHTML 属性
  2. 三者的区别是什么?
    • 元素 .innerText 属性 只识别文本,不能解析标签
    • 元素 .innerHTML 属性 能识别文本,能够解析标签
    • 如果还在纠结到底用谁,你可以选择 innerHTML

DOM 对象都是根据标签生成的,所以操作标签,本质上就是操作 DOM 对象。如果想要修改标签元素的里面的内容,则可以使用如下几种方式:

对象 .innerText 属性

// innerText 将文本内容添加/更新到任意标签位置
const intro = document.querySelector(".intro");
// intro.innerText = '嗨~ 我叫李雷!'
// intro.innerText = '<h4>嗨~ 我叫李雷!</h4>'

对象 .innerHTML 属性

// innerHTML 将文本内容添加/更新到任意标签位置
const intro = document.querySelector(".intro");
intro.innerHTML = "嗨~ 我叫韩梅梅!";
intro.innerHTML = `<h4>嗨~ 我叫韩梅梅!</h4>`;
总结

如果文本内容中包含 html 标签时推荐使用 innerHTML,否则建议使用 innerText 属性。

操作元素属性

操作元素常用属性

对象.属性 = 值;

// 1. 获取 img 对应的 DOM 元素
const pic = document.querySelector(".pic");
// 2. 修改属性
pic.src = "./images/lion.webp";
pic.width = 400;
pic.alt = "图片不见了...";

操作元素样式属性

  1. 设置/修改元素样式属性通过 style 属性引出来
  2. 如果需要修改一个 div 盒子的样式,比如 padding-left, 如何写?
    • element.style.paddingLeft = '300px'
    • 小驼峰命名法
  3. 因为我们是样式属性,一定别忘记,大部分数字后面都需要加单位。
  4. 使用 className 有什么好处?
    • 可以同时修改多个样式
  5. 使用 className 有什么注意事项?
    • 直接使用 className 赋值会覆盖以前的类名
  6. 使用 classNameclassList 的区别?
    • 修改大量样式的更方便
    • 修改不多样式的时候方便
    • classList 是追加和删除不影响以前类名

通过 style 属性操作 CSS

对象.style.样式属性 = 值;
<div class="intro">随便一些文本内容</div>
<script>
  // 获取 DOM 节点
  const box = document.querySelector(".intro");
  box.style.color = "red";
  box.style.width = "300px";
  // css 属性的 - 连接符与 JavaScript 的 减运算符
  // 冲突,所以要改成驼峰法
  box.style.backgroundColor = "pink";
</script>
注意

  1. 修改样式通过 style 属性引出
  2. 如果属性有 - 连接符,需要转换为小驼峰命名法
  3. 赋值的时候,需要的时候不要忘记加css 单位

操作类名 className 操作 CSS

// active 是一个 css 类名
元素.className = "active";
注意

  1. 由于 class 是关键字,所以使用 className 去代替
  2. className 是使用新值换旧值,如果需要添加一个类,需要保留之前的类名

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <style>
      div {
        width: 200px;
        height: 200px;
        background-color: pink;
      }

      .nav {
        color: red;
      }

      .box {
        width: 300px;
        height: 300px;
        background-color: skyblue;
        margin: 100px auto;
        padding: 10px;
        border: 1px solid #000;
      }
    </style>
  </head>

  <body>
    <div class="nav">123</div>
    <script>
      // 1. 获取元素
      const div = document.querySelector("div");
      // 2.添加类名  class 是个关键字 我们用 className
      div.className = "nav box";
    </script>
  </body>
</html>

通过 classList 操作类控制 CSS

// 追加一个类
元素.classList.add("类名");
// 删除一个类
元素.classList.remove("类名");
// 切换一个类
元素.classList.toggle("类名");
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <style>
      .box {
        width: 200px;
        height: 200px;
        color: #333;
      }

      .active {
        color: red;
        background-color: pink;
      }
    </style>
  </head>

  <body>
    <div class="box active">文字</div>
    <script>
      // 通过 classList 添加
      // 1. 获取元素
      const box = document.querySelector(".box");
      // 2. 修改样式
      // 2.1 追加类 add() 类名不加点,并且是字符串
      // box.classList.add('active')
      // 2.2 删除类  remove() 类名不加点,并且是字符串
      // box.classList.remove('box')
      // 2.3 切换类  toggle()  有还是没有啊,有就删掉,没有就加上
      box.classList.toggle("active");
    </script>
  </body>
</html>

操作 表单元素 属性

<input type="text" value="请输入" />
<button disabled>按钮</button>
<input type="checkbox" name="" id="" class="agree" />
<script>
  // 1. 获取元素
  let input = document.querySelector("input");
  // 2. 取值或者设置值  得到 input 里面的值可以用 value
  // console.log(input.value)
  input.value = "小米手机";
  input.type = "password";

  // 2. 启用按钮
  let btn = document.querySelector("button");
  // disabled 不可用   =  false  这样可以让按钮启用
  btn.disabled = false;
  // 3. 勾选复选框
  let checkbox = document.querySelector(".agree");
  checkbox.checked = false;
</script>

自定义属性

<div data-id="1">自定义属性</div>
<script>
  // 1. 获取元素
  let div = document.querySelector("div");
  // 2. 获取自定义属性值
  console.log(div.dataset.id);
</script>

定时器 - 间歇函数

  1. 定时器函数有什么作用?

    • 可以根据时间自动重复执行某些代码
  2. 定时器函数如何开启?

    • setInterval(函数名, 时间)
  3. 定时器函数如何关闭?

    let 变量名 = setInterval(函数,间隔时间);
    clearInterval(变量名);
    

定时器函数介绍

定时器间歇函数基本使用

开启定时器

setInterval(function, milliseconds)
// 第一个参数 function 是要执行的函数
// 第二个参数 milliseconds 是时间间隔,以毫秒为单位。
// 该函数会在每个时间间隔内重复执行。
// 每隔 1 秒钟输出一次“Hello World!”
setInterval(function () {
  console.log("Hello World!");
}, 1000);
注意

  1. 函数名字不需要加括号。
  2. setInterval() 函数返回一个计时器 ID,可以用来取消计时器。
  3. 间歇函数会一直重复执行,直到调用 clearInterval 方法停止它。因此,需要根据实际情况来判断何时停止间歇函数的执行
function repeat() {
  console.log("Hello World!");
}

// 每隔 1 秒钟输出一次“Hello World!”
setInterval(repeat, 1000);

间歇函数缺点

  • 如果函数执行的时间比时间间隔还长,那么函数会在上一个执行完成之前再次执行,可能会导致函数重复执行的问题。此外,间歇函数也可能会在浏览器的后台标签中被暂停,导致函数的执行不准确。
  • setInterval() 函数会一直执行,直到计时器被取消或页面被关闭。因此,使用 setInterval() 函数时需要小心,避免出现性能问题。
  • 如果要停止计时器,请使用 clearInterval() 函数。

关闭定时器

clearInterval(intervalID);
// intervalID:必需,周期性执行的代码的标识符,由 setInterval() 函数返回。
// 使用 setInterval() 创建了一个定时器,并将它的 ID 存储在变量 timerId 中
var timerId = setInterval(function () {
  console.log("定时器执行");
}, 1000);

// 使用 clearInterval() 方法来关闭这个定时器
clearInterval(timerId);

综合案例 - 轮播图定时器版

轮播图定时器版 (codepen.io)

<div class="carousel">
  <div class="carousel-container">
    <!-- <div class="carousel-item active">
        <img src="https://img1.baidu.com/it/u=1831000000,1831000000&fm=26&fmt=auto&gp=0.jpg" alt="" />
      </div> -->
  </div>
  <div class="carousel-footer">
    <div class="carousel-mask"></div>
    <div class="carousel-tool">
      <a href="https://www.bilibili.com/bangumi/play/ep743775" target="_blank" rel="noopener noreferrer">
        <span>XY 密室今日开业!游戏开始!</span>
      </a>
      <ul>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
      </ul>
    </div>
    <div class="carousel-buttons">
      <button class="prev">&lt;</button>
      <button class="next">&gt;</button>
    </div>
  </div>
</div>
.carousel {
  width: 1000px;
  height: 630px;
  margin: 0 auto;
  overflow: hidden;
  position: relative;
}

.carousel .carousel-container {
  width: 100%;
  height: 550px;
  position: relative;
}

.carousel .carousel-container .carousel-item {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

.carousel .carousel-container .carousel-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.carousel .carousel-footer {
  width: 100%;
  height: 80px;
  position: relative;
  padding: 12px 12px 0 12px;
}

.carousel .carousel-footer .carousel-mask {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  background: linear-gradient(transparent, rgba(0, 0, 0, 0.8));
}

.carousel .carousel-footer .carousel-tool a {
  margin: 0;
  color: #fff;
  font-size: 18px;
  margin-bottom: 10px;
  text-decoration: none;
}

.carousel .carousel-footer .carousel-tool a:hover {
  text-decoration: underline;
}

.carousel .carousel-footer .carousel-tool ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

.carousel .carousel-footer .carousel-tool ul li {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: #fff;
  margin: 10px 5px 0 5px;

  opacity: 0.4;
  cursor: pointer;
}

.carousel .carousel-footer .carousel-tool ul li.active {
  width: 12px;
  height: 12px;
  opacity: 1;
  /* background-color: #ff0000; */
}

.carousel .carousel-footer .carousel-buttons {
  position: absolute;
  right: 0;
  top: 12px;
  display: flex;
}

.carousel .carousel-footer .carousel-buttons button {
  width: 30px;
  height: 30px;
  margin-right: 40px;
  border-radius: 5px;
  border: none;
  background-color: rgba(255, 255, 255, 0.1);
  color: #fff;
  font-size: 20px;
  cursor: pointer;
  outline: none;
}

.carousel .carousel-footer .carousel-buttons button:hover {
  background-color: rgba(255, 255, 255, 0.2);
}
const sliderData = [
  {
    url: "https://i1.hdslb.com/bfs/archive/81584c757a6b4c71dc93170664745167b175dd72.jpg@976w_550h_1c.webp",
    title: "对人类来说会不会太超前了?",
    color: "rgb(100, 67, 68)",
  },
  {
    url: "https://i1.hdslb.com/bfs/archive/66faf0db298d9e61228283628064212e4c3152f8.jpg@976w_550h_1c.webp",
    title: "开启剑与雪的黑暗传说!",
    color: "rgb(43, 35, 26)",
  },
  {
    url: "https://i1.hdslb.com/bfs/archive/2a3b28a76cdbe112df557b453600e4c1c98bd3d0.jpg@976w_550h_1c.webp",
    title: "真正的 jo 厨出现了!",
    color: "rgb(36, 31, 33)",
  },
  {
    url: "https://i0.hdslb.com/bfs/archive/d7a15ce7bccdaf3ff0a41e2b2c80feac1f9edc82.jpg@976w_550h_1c.webp",
    title: "李玉刚:让世界通过 B 站看到东方大国文化",
    color: "rgb(139, 98, 66)",
  },
  {
    url: "https://i2.hdslb.com/bfs/archive/2f64c176864bced7835d375c47c2de700a107f93.jpg@976w_550h_1c.webp",
    title: "快来分享你的寒假日常吧~",
    color: "rgb(67, 90, 92)",
  },
  {
    url: "https://i2.hdslb.com/bfs/archive/b1a07a8baefa0694760cd6d99f212bee45d1333d.jpg@976w_550h_1c.webp",
    title: "哔哩哔哩小年 YEAH",
    color: "rgb(166, 131, 143)",
  },
  {
    url: "https://i0.hdslb.com/bfs/archive/67c3bbae0eec01a1783f35851649724cb4c408bd.jpg@976w_550h_1c.webp",
    title: "一站式解决你的电脑配置问题!!!",
    color: "rgb(53, 29, 25)",
  },
  {
    url: "https://i1.hdslb.com/bfs/archive/55ce9a4d1797ec56a0d4ed727f1a279b89ec3664.jpg@976w_550h_1c.webp",
    title: "谁不想和小猫咪贴贴呢!",
    color: "rgb(99, 72, 114)",
  },
];

const sliderContainer = document.querySelector(".carousel .carousel-container");
let count = 0;
setInterval(function () {
  count++;
  if (count >= sliderData.length) {
    count = 0;
  }
  sliderContainer.innerHTML = "";
  let sliderItem = document.createElement("div");
  sliderItem.className = "carousel-item";

  sliderItemImg = document.createElement("img");
  sliderItemImg.src = sliderData[count].url;
  sliderItemImg.referrerPolicy = "no-referrer";

  sliderItem.appendChild(sliderItemImg);
  sliderContainer.appendChild(sliderItem);

  const sliderFooter = document.querySelector(".carousel .carousel-footer");
  sliderFooter.style.backgroundColor = sliderData[count].color;

  const sliderFooterTitle = document.querySelector(".carousel .carousel-footer .carousel-tool a span");
  sliderFooterTitle.innerText = sliderData[count].title;

  const sliderFooterUl = document.querySelector(".carousel .carousel-footer .carousel-tool ul");
  const sliderFooterLi = sliderFooterUl.querySelectorAll("li");
  sliderFooterLi.forEach((item, index) => {
    if (index === count) {
      item.classList.add("active");
    } else {
      item.classList.remove("active");
    }
  });
}, 2000);

作业

网页时钟(图形版)

网页时钟(图形版) (codepen.io)

<!--
  - 需求:网页时钟(图形版)
  - 分析:
    - 创建日期对象 获取当前时间
    - 多次定时器,重复获取时间,让指针动起来
-->
<div class="clock">
  <div class="hand hour-hand"></div>
  <div class="hand minute-hand"></div>
  <div class="hand second-hand"></div>
</div>
.clock {
  width: 600px;
  height: 600px;
  margin: 50px auto;
  position: relative;
  background: url("https://s2.loli.net/2023/04/23/aKd5qAhiJ7jB8Dy.jpg") no-repeat;
}

.hand {
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
}

.hour-hand {
  background: url("https://s2.loli.net/2023/04/23/kKr5EMIBp6RLCjN.png") no-repeat center;
}

.minute-hand {
  background: url("https://s2.loli.net/2023/04/23/6RLfvyu1bG2rseT.png") no-repeat center;
}

.second-hand {
  background: url("https://s2.loli.net/2023/04/23/PBpfJsNwSZbnDFH.png") no-repeat center;
}
const hourHand = document.querySelector(".hour-hand");
const minuteHand = document.querySelector(".minute-hand");
const secondHand = document.querySelector(".second-hand");

function setDate() {
  const now = new Date();
  console.log(now);

  const seconds = now.getSeconds();
  const secondsDegrees = (seconds / 60) * 360;
  secondHand.style.transform = `rotate(${secondsDegrees}deg)`;

  const minutes = now.getMinutes();
  const minutesDegrees = (minutes / 60) * 360 + (seconds / 60) * 6;
  minuteHand.style.transform = `rotate(${minutesDegrees}deg)`;

  const hours = now.getHours();
  const hoursDegrees = (hours / 12) * 360 + (minutes / 60) * 30;
  hourHand.style.transform = `rotate(${hoursDegrees}deg)`;
}

setInterval(setDate, 1000);

焦点图案例

焦点图案例 (codepen.io)

<!-- QQ 音乐 10 屏轮播图  -->
<div class="qq-music__wrapper">
  <img class="qq-music__pic" src="https://s2.loli.net/2023/04/24/IMi9VWmCfLDekPG.webp" alt="" />
  <div class="qq-music__content">
    <h3 class="qq-music__content__title">挑战云歌单,欢迎你来</h3>
  </div>
</div>
.qq-music__wrapper {
  width: 700px;
  height: 320px;
  margin: 50px auto;
  background-color: #000;
  position: relative;
}

.qq-music__content {
  width: 700px;
  height: 53px;
  line-height: 53px;
  position: absolute;
  bottom: 0px;
  background-color: rgba(0, 0, 0, 0.8);
  z-index: 10;
}

.qq-music__content__title {
  width: 82%;
  margin: 0;
  margin-right: 20px;
  padding-left: 20px;
  color: #98e404;
  font-size: 28px;
  float: left;
  font-weight: 500;
  font-family: "Microsoft Yahei", Tahoma, Geneva;
}
const data = [
  {
    imgSrc: "https://s2.loli.net/2023/04/24/IMi9VWmCfLDekPG.webp",
    title: "挑战云歌单,欢迎你来",
  },
  {
    imgSrc: "https://s2.loli.net/2023/04/24/CwdqPzyf924uBTQ.webp",
    title: "田园日记,上演上京记",
  },
  {
    imgSrc: "https://s2.loli.net/2023/04/24/vE4siDBoaylFmPr.webp",
    title: "甜蜜攻势再次回归",
  },
  {
    imgSrc: "https://s2.loli.net/2023/04/24/gIQR7XDynqfv1od.webp",
    title: "我为歌狂,生为歌王",
  },
  {
    imgSrc: "https://s2.loli.net/2023/04/24/b5wN1fdsyvzP27r.webp",
    title: "年度校园主题活动",
  },
  {
    imgSrc: "https://s2.loli.net/2023/04/24/EAjuD8hv9kocUb5.webp",
    title: "pink 老师新歌发布,5 月 10 号正式推出",
  },
  {
    imgSrc: "https://s2.loli.net/2023/04/24/UIp9orDSFkvT87O.webp",
    title: "动力火车来到西安",
  },
  {
    imgSrc: "https://s2.loli.net/2023/04/24/laO39sJqpjLwyoi.webp",
    title: "钢铁侠 3,英雄镇东风",
  },
  {
    imgSrc: "https://s2.loli.net/2023/04/24/CRSn2pu3yvt9gTi.webp",
    title: "我用整颗心来等你",
  },
];

const pic = document.querySelector(".qq-music__pic");
const title = document.querySelector(".qq-music__content__title");

let index = 0;
setInterval(function () {
  index++;
  if (index >= data.length) {
    index = 0;
  }
  pic.src = data[index].imgSrc;
  title.innerHTML = data[index].title;
}, 1000);