Skip to content

2-2样式操作及案例(一) ​

本页对应 第二章WebAPIs,共 5 段视频,约 32 分钟。

学习目标 ​

  • 能获取指定元素,并对其常用属性(如 src、href、title、alt)完成读取、修改、新增和删除操作。
  • 能使用 Math.random() 与 Math.floor() 从图片地址数组中随机取值,并修改图片元素的 src 实现刷新随机显示图片。
  • 能通过 element.style.属性名 修改元素内联样式,正确使用小驼峰命名并补充必要 CSS 单位。
  • 能获取 body 元素,并使用 style.backgroundImage 配合 url() 与模板字符串实现随机背景图片切换。
  • 能通过 className 为元素添加或替换类名以修改样式,并说明原类名被覆盖的问题及保留多个类名的写法。
  • 能使用 setInterval 创建间隔定时器,并按指定周期执行回调,能根据需求清除定时器。

知识点 ​

操作元素内容:innerText 与 innerHTML ​

为什么需要:DOM 对象可以操作页面标签,本质上就是操作 DOM 对象(增删改查)。要改标签里显示的文字,就要用 innerText 或 innerHTML。怎么想:先获取元素对象,再读或写它的内容属性;查是直接打印,改/增是赋新值,删是赋空字符串。怎么做:

html
<script>
  // 操作DOM元素内容
  // 1. 对象.innerText 增删改查
  // 1.1 查
  console.log(box.innerText)  // 古丽扎娜
  // 1.2 改
  box.innerText = '迪丽热巴'
  // 1.3 增
  const box1 = document.querySelector('.box1')
  console.log(box1)
  box1.innerText = '佟丽丫丫'
  // 1.4 删  给空字符串可以删除内容
  box.innerText = ''
  box1.innerText = ''
</script>

innerText 将文本内容添加/更新到任意标签位置,文本中包含的标签不会被解析。innerHTML 同样能添加/更新内容,但文本中包含的标签会被解析:

html
<script>
  // 2. 对象.innerHTML  会解析标签
  box.innerHTML = '<strong>迪丽热巴</strong>'
</script>

易错点:如果文本内容中包含 html 标签时推荐使用 innerHTML,否则建议使用 innerText;删除内容不是删元素,而是把内容赋成空字符串。

年会抽奖案例:随机抽取且不重复 ​

为什么需要:练习用 innerText 把随机名字写进 span,并用数组删除避免重复中奖。怎么想:先用 Math.random() 取数组下标,把名字写入对应盒子,再用 splice(随机数,1) 删除刚抽出的名字。怎么做:

html

<!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>年会抽奖</title>
  <style>
    .wrapper {
      width: 840px;
      height: 420px;
      background: url(./images/bg01.jpg) no-repeat center / cover;
      padding: 100px 250px;
      box-sizing: border-box;
    }

    .wrapper span {
      color: #b10e0d;
    }
  </style>
</head>

<body>
  <div class="wrapper">
    <strong>年会抽奖</strong>
    <h1>一等奖:<span class="one">???</span></h1>
    <h3>二等奖:<span class="two">???</span></h3>
    <h5>三等奖:<span class="three">???</span></h5>
  </div>

  <script>
    // 数组
    const arr = ['迪丽热巴', '古丽扎娜', '佟丽丫丫', '马尔扎哈']
    // 1. 一等奖的做法
    // 1.1 利用随机数选取数组中的名字
    const random = Math.floor(Math.random() * arr.length)
    console.log(random) // 0 ~ 3 之间的随机整数
    console.log(arr[random]) // 随机名字

    // 1.2 把名字放入对应的盒子里面 span
    const one = document.querySelector('.one')
    one.innerText = arr[random]

    // 1.3 不允许重复抽奖,所以要把刚才选出来的名字从数组中删除
    // arr.splice(随机数, 1)  // 可以删除刚才抽取的名字
    arr.splice(random, 1)
    console.log(arr)

    // 2. 二等奖的做法
    // 2.1 利用随机数选取数组中的名字
    const random2 = Math.floor(Math.random() * arr.length)
    console.log(arr[random2]) // 数组里面的名字

    // 2.2 把名字放入对应的盒子里面 span
    const two = document.querySelector('.two')
    two.innerText = arr[random2]

    // 2.3 不允许重复抽奖,所以要把刚才选出来的名字从数组中删除
    arr.splice(random2, 1)
    console.log(arr)

    // 3. 三等奖的做法
    // 3.1 利用随机数选取数组中的名字
    const random3 = Math.floor(Math.random() * arr.length)
    console.log(arr[random3]) // 数组里面的名字

    // 3.2 把名字放入对应的盒子里面 span
    const three = document.querySelector('.three')
    three.innerText = arr[random3]

    // 3.3 不允许重复抽奖,所以要把刚才选出来的名字从数组中删除
    arr.splice(random3, 1)
    console.log(arr)
  </script>
</body>

</html>

易错点:随机下标要用 Math.floor(Math.random()*arr.length);每次抽完必须从数组中删除,否则可能重复;写入用 innerText 即可。

操作元素常用属性 ​

为什么需要:DOM 不仅能改内容,也能改标签自带属性,比如图片 src、链接 href、title、alt。怎么想:先获取元素,再“对象.属性”读写;有该属性赋新值就是改,没有就是增,赋空字符串可删值。怎么做:

html
<script>
  // 1. 先获取这个元素
  const img = document.querySelector('img')
  // 2. 操作DOM元素常见属性
  // 2.1 查
  console.log(img.src)
  // 2.2 改
  img.src = './images/3.png'
  // 2.3 增
  img.title = '我是播仔,我是不是很可爱'
  // 2.4 删
  img.alt = ''
</script>

随机背景案例:

html

<!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>随机显示图片案例</title>
  <style>
    img {
      width: 600px;
    }
  </style>
</head>

<body>
  <img src="./images/1.png" alt="">
  <script>
    // 随机显示图片案例
    // 图片地址
    const arr = [
      './images/1.png',
      './images/2.png',
      './images/3.png',
      './images/4.png'
    ]
    // 获取图片元素
    const img = document.querySelector('img')

    // 1. 利用随机数抽取数组中的一个地址
    const random = Math.floor(Math.random() * arr.length)
    console.log(arr[random]) // 得到图片地址

    // 2. 把地址赋值给图片src属性
    img.src = arr[random]
  </script>
</body>

</html>

易错点:属性名直接写,不要加多余前缀;改 src 时路径要写对;转写稿中演示了鼠标放图上能看到 title,删 alt 可赋空字符串。

通过 style 操作样式 ​

为什么需要:很多效果要动态改样式,如小圆点换色、图片滚动位置变化。怎么想:样式也在对象里,通过 对象.style.样式属性 修改。怎么做:

轮播图小圆点与图片滚动效果示意

html
<script>
  // 通过style操作元素样式
  // 1. 先要获取这个box元素对象
  const box = document.querySelector('.box')

  // 2. 通过style来从操作样式
  box.style.width = '300px'
  box.style.marginTop = '50px'
  box.style.backgroundColor = 'skyblue'

  // 3. 注意事项
  // 3.1 给样式赋值的时候,千万不要忘了加单位比如 300px
  // 3.2 如果有-的样式,我们采取的是小驼峰命名法比如 marginTop
  // 3.3 一定不要忘了加 style 属性
</script>

易错点:赋值要加 CSS 单位;有短横线的样式转小驼峰,如 margin-top 写成 marginTop;别忘写 style。转写稿调试时演示:300 不加 px 不生效且无提示;写成 margin-top 会报错,改 marginTop 才生效;backgroundColor 的 C 要大写。

className 与 classList 操作类样式 ​

为什么需要:样式多时逐条写 style 很繁琐,可把多个样式放进一个类,再把类加到元素上。怎么想:className 是整体换类名,会覆盖旧类名;classList 可追加、删除、切换,更推荐。怎么做:

html
<script>
  // 通过类名操作元素样式
  // 1. 获取box盒子
  const box = document.querySelector('.box')
  // 2. 利用类名操作元素样式
  // box.className = 'circle'
  box.className = 'box circle'
  // 3. 利用类名操作样式添加的新的类名会覆盖掉原先的类名
</script>

classList 追加、删除、切换类名示意

html
<script>
  // 1. 获取box盒子
  const box = document.querySelector('.box')
  // 2.通过classList操作元素样式(推荐)
  // 2.1 追加类名
  // box.classList.add('circle')
  // 2.2 删除类名
  // box.classList.remove('box')
  // 2.3 切换类名: 如果元素身上有这个类名,那么就删除,如果没有这个类名则添加
  box.classList.toggle('circle')
</script>

易错点:class 是关键字,用 className;className 是新值换旧值,需保留旧类名时写成 'box circle';转写稿中直接写 circle 会丢掉 box,导致原宽高等样式失效。

操作表单元素属性 ​

为什么需要:表单常要改 type、value,或控制禁用、勾选。怎么想:普通属性用“DOM对象.属性=新值”;disabled、checked、selected 这类布尔属性用 true/false。怎么做:

html
<script>
  // 操作表单属性
  // 1. 操作表单 type 和 value 属性
  // 1.1 修改type属性
  const username = document.querySelector('[name=username]')
  console.log(username)
  // username.type = 'password'

  // 1.2 操作表单的 value 属性
  // console.log(username.value)  // 查
  // username.value = '用户名试试'  // 增
  // username.value = '请输入用户名' // 改
  // username.value = ''  // 删

  // 2. 禁用按钮或者是勾选复选框  布尔型
  // 2.1 禁用按钮  
  const button = document.querySelector('button')
  // button.disabled = true  // true 是禁用
  button.disabled = false  // false 是不禁用

  // 2.2 勾选复选框
  const agree = document.querySelector('[name=agree]')
  console.log(agree)
  // agree.checked = true // true 是选中复选框
  agree.checked = false // flase 是不选中复选框
</script>

易错点:布尔属性不要写字符串 'true';disabled=true 是禁用,false 是不禁用;checked=true 是选中。

自定义属性:data- 与 dataset ​

为什么需要:有时要在标签上存业务数据,标准属性不够用。怎么想:HTML5 用 data- 开头定义自定义属性,DOM 对象上用 dataset 获取。怎么做:

html
<script>
  // 自定义属性
  // 1. 获取盒子
  const box = document.querySelector('.box')

  // 2. 得到自定义属性值
  // console.log(box.dataset)  // 得到一个对象集合
  // console.log(box.dataset.id) // 1
  // console.log(box.dataset)  // 得到一个对象集合
  console.log(box.dataset.name) // box
</script>

易错点:标签上写 data- 开头,DOM 上通过 dataset 取;不要和 class、id、title 等标准属性混用;dataset 拿到的是集合对象,再点具体属性名取值。

材料说明与本节范围 ​

本节笔记主题是“定时器-间隔函数”,核心是 setInterval 的开启与关闭。笔记中没有图片,因此无图片可保留;下面保留笔记中的两段代码,并围绕它们扩写。需要说明:提供的转写稿讲的是操作元素常见属性、随机图片、style、类名等内容,与本节“定时器-间隔函数”不匹配,不能把其中的推导和调试过程硬套到定时器上,否则会编造。因此以下只依据本节笔记扩写,不引入转写稿中无关知识点。

为什么需要间隔定时器 ​

为什么需要: 网页中有些功能不能只靠用户点击触发,而是需要“每隔一段时间自动执行一段代码”。笔记给出的典型场景是网页中的倒计时。倒计时需要持续、重复地更新,不可能让用户每秒手动点一次。

怎么想: 先明确“自动”和“重复”两个关键词。自动,意味着不靠手动触发;重复,意味着不是执行一次就结束,而是按固定间隔反复执行。于是需要一种机制:把要重复执行的代码交给定时器,并告诉它间隔多久执行一次。

怎么做: JavaScript 内置了定时器函数,笔记说明定时器函数有两种:间隔函数和延迟函数。本节只讲间隔函数 setInterval。它的作用是间隔固定的时间自动重复执行另一个函数,也叫定时器函数。

易错点: 不要把“间隔函数”和“延迟函数”混为一谈;本节笔记只展开 setInterval,延迟函数不在本节范围内,不能凭感觉补细节。

开启定时器:setInterval 的基本写法 ​

为什么需要: 要实现“每隔一段时间自动执行”,就要先学会开启定时器。开启后才能让一段函数按固定间隔重复运行。

怎么想: setInterval 需要两个关键信息:一是“要重复执行什么”,也就是一个函数;二是“隔多久执行一次”,也就是间隔时间。把这两件事按语法位置写进去即可。

怎么做: 笔记给出的语法如下,代码原样保留:

html
<script>
  setInterval(function () {
    console.log('我是1秒钟执行一次')
  }, 1000)
</script>

这段代码中,第一个参数是一个匿名函数,里面写要重复执行的代码;第二个参数是 1000。笔记强调:setInterval 的作用是每隔一段时间调用这个函数;间隔时间单位是毫秒。

易错点: 最容易错的是单位。1000 毫秒才是 1 秒,不要写成 1 就以为是一秒。另一个易错点是函数的位置:这里传入的是函数本身,定时器到时间后才会调用它;不能把“要执行的代码”随便写在 setInterval 外面,否则就失去定时重复执行的意义。

关闭定时器:保存返回值再 clearInterval ​

为什么需要: 定时器一旦开启会反复执行,如果某些条件下需要停止,就必须能关闭它。笔记明确指出:需要定时器变量名来关闭。

怎么想: 关闭的前提是“能找到这个定时器”。setInterval 执行后会返回一个唯一的数字,笔记用 timer、timer1 保存返回值,并打印出 1、2。因此思路是:开启时把返回值存到变量里,关闭时把这个变量交给 clearInterval。

怎么做: 笔记代码如下,代码原样保留:

html
<script>
  let timer = setInterval(repeat, 1000)  // 注意调用的时候直接写函数名字不需要写小括号
  console.log(timer) //  1
  let timer1 = setInterval(repeat, 1000)  // 注意调用的时候直接写函数名字不需要写小括号
  console.log(timer1) //  2
  // 2. 关闭定时器
  clearInterval(timer)

</script>

从这段代码可以看到:setInterval(repeat, 1000) 中直接写函数名 repeat,不写小括号;返回值分别保存到 timer 和 timer1;最后用 clearInterval(timer) 关闭 timer 对应的定时器。

易错点: 第一,关闭定时器要传“保存返回值的变量”,不是传函数名。第二,笔记强调调用时直接写函数名字不需要写小括号;如果写成 repeat(),含义会变成先执行函数并把结果交给定时器,而不是把函数交给定时器之后按间隔调用。第三,代码中的 repeat 必须是已经定义好的函数,否则运行会报错;笔记重点在语法结构,没有展开 repeat 的函数体。第四,返回的数字虽然示例是 1、2,但笔记只说明它是唯一数字,实际使用时应保存变量,不要依赖具体数字。

调试观察与使用建议 ​

为什么需要: 定时器是“异步重复执行”,只看代码不容易确认是否按预期运行,需要观察输出和关闭效果。

怎么想: 可以先在回调里写 console.log,观察是否按间隔重复打印;再把 setInterval 的返回值打印出来,确认拿到唯一数字;最后调用 clearInterval,观察是否停止。

怎么做: 按笔记示例,在控制台查看 timer 和 timer1 的输出;关闭时执行 clearInterval(timer)。若开启多个定时器,要分别用不同变量保存,关闭哪个就传哪个变量。

易错点: 不要开启多个定时器却只保存一个变量,否则容易关错或无法关闭其他定时器;关闭后原变量仍存在,但对应定时器已停止,不要误以为变量消失;间隔时间单位始终是毫秒。

课件图示 ​

课件第68页:描述 属性/方法 效果 获取DOM对象 document.querySelect

课件第64页:五、定时器-间隔函数 l 网页中经常会需要一种功能:每隔一段时间需要自动执行一段

课件第65页:五、定时器-间隔函数 定时器函数可以开启和关闭定时器 1. 开启定时器 Ø 作用

课件第66页:五、定时器-间隔函数 定时器函数可以开启和关闭定时器 2. 关闭定时器 一般不会

课件第67页:总结 总结 1. 定时器间隔函数有什么作用? Ø可以每隔指定时间自动重复执行某些

课件第33页:三、操作元素内容 l DOM对象可以操作页面标签,所以本质上就是操作DOM对象(

课件第34页:三、操作元素内容 1. 元素.innerText 属性 Ø "渲染"文本内容到标

课件第35页:三、操作元素内容 2. 元素.innerHTML 属性 Ø "渲染"文本内容到标

代码示例 ​

示例一:操作元素内容(innerText / innerHTML) ​

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

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>操作元素内容</title>
  <style>
    .box,
    .box1 {
      width: 240px;
      height: 60px;
      line-height: 60px;
      text-align: center;
      background-color: pink;
      margin-bottom: 10px;
    }
  </style>
</head>

<body>
  <div class="box">古丽扎娜</div>
  <div class="box1">???</div>

  <script>
    // 操作DOM元素内容
    // 1. 对象.innerText 增删改查
    // 1.1 查
    const box = document.querySelector('.box')
    console.log(box.innerText)  // 古丽扎娜
    // 1.2 改
    box.innerText = '迪丽热巴'
    // 1.3 增
    const box1 = document.querySelector('.box1')
    console.log(box1)
    box1.innerText = '佟丽丫丫'
    // 1.4 删  给空字符串可以删除内容
    // box.innerText = ''
    // box1.innerText = ''

    // 2. 对象.innerHTML  会解析标签
    box.innerHTML = '<strong>迪丽热巴</strong>'
  </script>
</body>

</html>

关键行与易错点

  • box.innerText:读取标签内部的文本内容,是「查」;box.innerText = '迪丽热巴' 是「改」(原来没有的属性名赋值就是「增」)。
  • box.innerText = '':给空字符串就是「删」,页面上文字会消失,但标签还在。
  • innerText 不会解析字符串里的标签,写成 '<strong>迪丽热巴</strong>' 会原样把尖括号显示出来;innerHTML 会解析标签,<strong> 会变成真正的加粗元素。
  • 总结:文本里包含 html 标签时用 innerHTML,否则建议用 innerText。

示例二:随机显示图片案例(操作元素常用属性 src) ​

html
<!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>随机显示图片案例</title>
  <style>
    img {
      width: 600px;
    }
  </style>
</head>

<body>
  <img src="./images/1.png" alt="">
  <script>
    // 随机显示图片案例
    // 图片地址
    const arr = [
      './images/1.png',
      './images/2.png',
      './images/3.png',
      './images/4.png'
    ]
    // 获取图片元素
    const img = document.querySelector('img')

    // 1. 利用随机数抽取数组中的一个地址
    const random = Math.floor(Math.random() * arr.length)
    console.log(arr[random]) // 得到图片地址

    // 2. 把地址赋值给图片src属性
    img.src = arr[random]

    // ---- 操作常见属性的增删改查(与上面同一个 img 对象)----
    // 查
    console.log(img.src)
    // 改
    // img.src = './images/3.png'
    // 增(原来没有 title 属性,赋值即新增)
    // img.title = '我是播仔,我是不是很可爱'
    // 删(给空字符串即可)
    // img.alt = ''
  </script>
</body>

</html>

关键行与易错点

  • 必须先 document.querySelector('img') 拿到 DOM 对象,之后才能 img.src = ...;属性名直接点出来,不需要 setAttribute。
  • 随机下标必须是 Math.floor(Math.random() * arr.length),Math.random() 只产生 0 ~ 1 的小数,不取整会取不到数组元素。
  • 路径要写成和页面一致的相对路径(如 ./images/1.png),文件不存在时图片就是裂图,容易误以为代码写错。
  • 「增 / 改 / 删」都靠赋值完成:原来有这个属性 → 改;原来没有 → 增;赋空字符串 → 相当于删除该属性值。

示例三:通过 style / className / classList 操作元素样式 ​

html
<!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>操作元素样式属性</title>
  <style>
    .box {
      width: 200px;
      height: 200px;
      background-color: pink;
    }

    .circle {
      border-radius: 50%;
      background-color: skyblue;
      text-align: center;
      line-height: 200px;
    }
  </style>
</head>

<body>
  <div class="box">播仔</div>

  <script>
    // 1. 先获取这个box元素对象
    const box = document.querySelector('.box')

    // 2. 通过style来操作样式
    box.style.width = '300px'
    box.style.marginTop = '50px'
    box.style.backgroundColor = 'skyblue'

    // 3. 通过 className 操作样式(新值换旧值)
    // box.className = 'circle'          // 原来的 box 类名被覆盖掉了
    // box.className = 'box circle'      // 想保留旧类名,用空格隔开

    // 4. 通过 classList 操作样式(推荐)
    // box.classList.add('circle')       // 追加类名
    // box.classList.remove('box')       // 删除类名
    // box.classList.toggle('circle')    // 有则删、无则加
  </script>
</body>

</html>

关键行与易错点

  • 修改样式必须走 box.style.xxx,只写 box.width 是没效果的(所有样式都在 style 里面)。
  • 赋值要带单位:'300px' 不能写成 300,少了 px 既不报错也不生效,最难排查。
  • 带 - 的样式要转小驼峰:margin-top → marginTop、background-color → backgroundColor。
  • className = 'circle' 是替换,原来的 box 类名会丢失,宽高样式就失效了;要保留旧类名得写成 'box circle'。
  • 更推荐 classList:add / remove / toggle 只在原有类名基础上增删,不会覆盖旧类名。

常见错误 ​

1. 改样式时数字不带单位

  • 现象:box.style.width = 300 执行后页面毫无变化,控制台也不报错。
  • 原因:style 上的属性值最终是 CSS 字符串,纯数字对 width、margin-top 等长度类属性不合法,浏览器会静默丢弃。
  • 修法:写成 '300px';只有无单位属性(opacity、zIndex、lineHeight 的无单位值)才可以直接写数字。

2. 漏写 .style,或把连字符属性名原样搬过来

  • 现象:box.width = '300px' 没反应;box.style.background-color = 'red' 直接语法报错。
  • 原因:width 不是元素自带属性,只是给对象加了一个没人读取的自有属性;而 background-color 里的 - 被解析成减号运算。
  • 修法:一律 对象.style.属性名,多单词改成小驼峰 backgroundColor、marginTop。

3. className 赋值把原有类名顶掉

  • 现象:给盒子加了个 circle 类之后,原来的宽高、背景全失效,页面布局塌了。
  • 原因:className 是"整串替换"而不是追加,'circle' 覆盖了原来的 'box'。
  • 修法:要么手动拼回 box.className = 'box circle',要么直接用 classList.add('circle') / classList.toggle('circle') 做增删,不必关心原有类名。

4. 用 innerText 塞标签字符串,或用 innerHTML 塞用户输入

  • 现象:页面上明晃晃显示 <strong>迪丽热巴</strong> 这串字;或者输入框内容被当作 HTML 渲染出来。
  • 原因:innerText 只认纯文本、不解析标签;innerHTML 会解析并执行标签,外部输入直接进 DOM 就是 XSS 入口。
  • 修法:需要渲染结构才用 innerHTML;纯文本(尤其是用户数据)用 innerText / textContent,或用 document.createElement 拼节点。

5. 表单布尔属性用字符串赋值

  • 现象:btn.disabled = 'false'、checkbox.checked = 'false',控件依然处于禁用 / 勾选状态。
  • 原因:disabled、checked、selected 这类布尔属性只看"属性存不存在",任何非空字符串都算存在,'false' 也是真。
  • 修法:只赋 true / false 布尔值,不要加引号。

6. 自定义属性读错位置

  • 现象:<div data-user-id="7">,box.userId、box.data-userId 全是 undefined。
  • 原因:data-* 不挂在元素自身的普通属性上,而是集中在 dataset 集合里,且连字符段要转小驼峰。
  • 修法:box.dataset.userId;调试时先 console.log(box.dataset) 看全集。

7. 定时器写成函数调用,或句柄丢失导致关不掉

  • 现象:setInterval(repeat(), 1000) 只跑一次(甚至立刻执行完就没动静);按钮连点几次后数字越跳越快,clearInterval 停不下来。
  • 原因:传的是函数执行结果而不是函数本身;timer 声明在函数内部每次都是新变量,且重复点击时旧的定时器从未被清除。
  • 修法:传函数引用 setInterval(repeat, 1000) 或箭头函数;timer 用外层 let 保存,并在开启前先 clearInterval(timer) 兜底。

练习 ​

练习 1|文案与结构切换 页面上有 <div class="msg"></div>,用一个按钮在两种状态间切换:点击后显示"温馨提示:请先登录"(em 要斜体生效),再点一次恢复成纯文本"温馨提示:请先登录"(<em> 原样显示为字符)。 要求:只用一次 if/else,不新增元素。

练习 2|样式三连改 有一个 200×200 的 .box。用 style 一次性把它改成宽 300px、上外边距 50px、背景 skyblue;随后再写一段代码,用类名方式把它变成圆形并水平垂直居中(已备好 .circle 类)。 要求:两种写法都写出来,并说明第二次改写时为什么不能只写 box.className = 'circle'。

练习 3|登录框的"显示密码" 一个密码输入框和"眼睛"按钮。点击按钮在 password / text 之间切换输入框类型,同时按钮文字在"显示密码"/"隐藏密码"间切换。 要求:用同一个按钮完成切换,不写两个按钮。

练习 4|抽奖升级版 4 人名单,抽出三等奖、二等奖、一等奖各 1 人,不能重复。 要求:把笔记里三段复制粘贴的代码改成一次循环(或一个函数调用三次),并说明为什么必须"先取值、后 splice"。

练习 5|倒计时与清理 页面显示 10 秒倒计时,到 0 停止并显示"时间到"。 要求:写出开启与关闭的完整代码;再补一句说明:如果不保存 setInterval 的返回值会发生什么。

参考要点:

  1. 分支内分别用 msg.innerHTML = '...<em>...</em>' 与 msg.innerText = '...<em>...</em>'。
  2. box.style.width='300px'; box.style.marginTop='50px'; box.style.backgroundColor='skyblue'; 第二段用 classList.add('circle');因为 className 是替换,直接赋 'circle' 会丢掉 box 类里原有的尺寸样式。
  3. 用一个 let flag = false(或直接判断 input.type),在 'password' 与 'text' 之间切换,并同步 btn.innerText。
  4. 循环内 const i = Math.floor(Math.random()*arr.length); span.innerText = arr[i]; arr.splice(i,1);——若先 splice 再取值,索引会错位甚至拿到 undefined。
  5. let timer = setInterval(fn, 1000),fn 内递减,到 0 时 clearInterval(timer);不保存返回值就没有句柄可传,定时器无法停止。

原视频对照 ​

#视频时长
1操作元素常见属性05:54
2随机显示图片案例03:54
3通过style来修改元素样式09:29
4随机显示背景图片案例05:54
5通过类名修改元素样式06:56

小结 ​

  1. 改内容先问"要不要渲染结构":要结构用 innerHTML,纯文本一律 innerText / textContent;用户输入永远走纯文本这条路。
  2. 属性操作是统一的"对象.属性 = 值"模型:查用读、改和增都是赋值、删给空字符串;能不能生效取决于这个属性是不是标签自带的。
  3. 改样式有三档,优先级从低到高:style 适合改一两处、需要动态计算值(如随机坐标)的场合;className 只作为"能看懂老代码"的知识点;日常首选 classList.add/remove/toggle。
  4. style 的三个死穴记牢:必须带 .style、连字符转小驼峰、长度值带单位——三者任一漏掉都是"不报错但不生效",排查成本最高。
  5. 布尔属性(disabled/checked/selected)只认真布尔值,字符串 'false' 会被当成"有属性"。
  6. 自定义数据统一走 data-* + dataset(连字符转小驼峰),这是把数据挂在 DOM 上再取回的标准姿势。
  7. setInterval 的返回值必须用外层变量接住,否则关不掉;重复触发的场景(点击、切换)要先 clearInterval 再开新的,避免叠加。
  8. 案例题的通用骨架就三步:取元素 → 随机/计算得到数据 → 把数据写回元素属性;随机不重复的关键是取完立刻从数组里删掉,索引和数组始终同步。