当前位置: 首页 > ai >正文

练习小项目7:天气状态切换器②

这是上一篇 练习小项目7:天气状态切换器-CSDN博客的扩展

扩展新功能:

  1. 自动轮播天气状态
  2. 添加“暂停/恢复轮播”按钮
  3. 文字添加淡入淡出动画

🧠 思路提示:

     添加“暂停/恢复轮播”按钮 

  1. 使用 setInterval 每隔几秒执行一次更新。

  2. i 是当前的天气索引,通过 (i + 1) % weatherData.length 实现循环。

    添加“暂停/恢复轮播”按钮 

  1. 新增按钮:在 HTML 中添加一个按钮,比如文字是“暂停”。

  2. 用变量保存定时器 ID:调用 setInterval 时会返回一个定时器 ID,存下来(如:let timer = setInterval(...))。

  3. 切换状态

    • 如果正在播放(有定时器),点击按钮时:

      • clearInterval(timer) 清除定时器;

      • 按钮文字改成“恢复”;

      • 状态变量(比如 isPlaying)设为 false

    • 如果已暂停(没有定时器),点击按钮时:

      • 重新调用 setInterval() 启动轮播;

      • 按钮文字改成“暂停”;

      • isPlaying 设为 true

    文字添加淡入淡出动画  

页面结构(HTML 参考): 

<div class="container"><h2 id="weatherText" class="fade">☀️ 晴天</h2><button id="changeBtn">切换天气</button><button id="pauseOrPlayBtn">暂停</button></div>

 实践代码如下: 

JS:

const weatherText = document.getElementById('weatherText')
const changeBtn = document.getElementById('changeBtn')
const pauseOrPlayBtn = document.getElementById('pauseOrPlayBtn')const weatherData = [{ icon: "☀️", text: "晴天", class: "sunny" },{ icon: "☁️", text: "多云", class: "cloudy" },{ icon: "🌧️", text: "雨天", class: "rainy" }
]let timer = null
let isPlay = truepauseOrPlayBtn.addEventListener('click', () => {isPlay = !isPlaypauseOrPlayBtn.textContent = !isPlay ? '恢复' : '暂停'if (!isPlay) {clearInterval(timer)} else {clearInterval(timer) // 避免重复timer = setInterval(() => {updateWeather((i + 1) % weatherData.length)}, 3000)}
})let i = 0
const updateWeather = (index) => {// 添加 fade-out 类,触发淡出weatherText.classList.add('fade-out')setTimeout(() => {// 更新文本weatherText.textContent = `${weatherData[index].icon} ${weatherData[index].text}`// 移除所有旧的 classweatherData.forEach(weather => {document.body.classList.remove(weather.class)})// 添加新的 classdocument.body.classList.add(weatherData[index].class)// 淡入weatherText.classList.remove('fade-out') // 变回 fade 状态}, 500)// 更新全局索引 ii = index
}
changeBtn.addEventListener('click', () => {// 每次调用时,传入下一个索引updateWeather((i + 1) % weatherData.length)
})timer = setInterval(() => {updateWeather((i + 1) % weatherData.length)
}, 3000);// 初始设置
updateWeather(0)
// 让界面初始化时更清晰,而不是说你不用设置按钮文字。而是要“主动设置一次”初始文字,不要依赖 HTML 里写死或者默认值
pauseOrPlayBtn.textContent = '暂停'

CSS:

body {transition: background-color 0.3s;font-family: sans-serif;text-align: center;padding-top: 50px;}.sunny {background-color: #ffe066;color: #333;}.cloudy {background-color: #d0d0d0;color: #333;}.rainy {background-color: #7f8fa6;color: white;}button {margin-top: 20px;padding: 10px 20px;}.fade {opacity: 1;transition: opacity 0.5s ease;}.fade-out {opacity: 0;}

页面效果展示 :

 

额外知识记录: 

✅为什么要在初始代码updateWeather(0)后设置pauseOrPlayBtn.textContent = '暂停' 初始化按钮的文字?

updateWeather(0)
pauseOrPlayBtn.textContent = '暂停'
  • 当网页刚加载时(在点击按钮之前),按钮上的文字是靠 HTML 中写的内容决定的。
  • 如果你忘记在 HTML 中写上默认文字,比如 <button id="pauseOrPlayBtn">暂停</button>那这个按钮一开始可能是空的
  • 所以为了保证按钮在加载时总是显示正确的文字,我们可以在 JS 的初始化代码里写一行pauseOrPlayBtn.textContent = '暂停'。

建议的本意是为了让界面初始化时更清晰,而不是说你不用设置按钮文字。而是要“主动设置一次”初始文字,不要依赖 HTML 里写死或者默认值

✅实现淡入淡出动画效果时,为什么要使用 setTimeout ?

如果你不使用 setTimeout,会发生这样的事: 

weatherText.classList.add('fade-out')
weatherText.textContent = "☁️ 多云" // 🔴 马上就换文字了!
weatherText.classList.remove('fade-out')

因为 JavaScript 执行太快,页面还没来得及显示“淡出”的过程,文字就已经换掉了,然后马上又“淡入”,视觉上就根本没有“淡出”的效果。所以使用 setTimeout,延迟文字替换。

步骤发生时机说明
添加 .fade-out立刻执行开始慢慢变透明
setTimeout(...)延迟 500ms 后执行内容已经淡出,此时换内容
移除 .fade-outsetTimeout开始淡入,慢慢显示新内容

 扩展一下:

setTimeoutvoid element.offsetWidth(在练习小项目3:随机正能量语录生成器-CSDN博客中使用到) 都是用来“强制浏览器触发样式重绘(reflow)或重排(repaint)”。但是不同的原理和机制。

1. void element.offsetWidth 的原理

  • 访问 element.offsetWidth 是读取元素的布局信息,浏览器会强制“同步计算”最新的布局状态,这就触发了浏览器的 回流(reflow)

  • 通过 void 取值(void element.offsetWidth)的写法,只是为了读取属性值而不使用它,目的是强制浏览器先完成这一步的计算。

  • 常用在:当你动态修改了元素的样式或类名后,想强制浏览器“立刻应用变化”,然后再执行下一步操作,比如添加动画类,从而确保动画能被正确触发。


2. setTimeout(fn, 0) 的原理

  • setTimeout 是把任务放到 事件队列的宏任务队列,在当前所有同步代码执行完后才执行。

  • 用它来“分割执行步骤”,让浏览器有机会先渲染、更新页面,然后再执行定时器中的代码。

  • 作用相当于“延迟执行”,间隔大约是几毫秒,保证样式修改和布局更新能被浏览器先处理。


区别总结

方式作用机制触发时机适用场景
void element.offsetWidth读取元素布局属性,触发同步回流立即同步触发,阻塞后续代码想立即强制刷新布局状态,配合CSS动画
setTimeout(fn, 0)异步延迟执行,放入宏任务队列等同步代码执行完成后再执行想分开两步执行,给浏览器时间渲染页面

举个简单比喻

  • void element.offsetWidth 就像你“马上打断别人,让他先确认一下现在状态”,同步立刻得到确认。

  • setTimeout(fn, 0) 就像说:“先让他忙完手头的事,等下再去问”,异步排队。

http://www.xdnf.cn/news/8314.html

相关文章:

  • 机器学习中的维度、过拟合、降维
  • 从制造到智造:猎板PCB的技术实践与产业价值重构
  • 攻防世界 - MISCall
  • JMeter-SSE响应数据自动化
  • SVN被锁定解决svn is already locked
  • 青少年编程与数学 02-020 C#程序设计基础 02课题、开发环境
  • FME入门系列教程7-基于FME的ArcGIS空间数据互操作技术研究与实践
  • 线程封装与互斥
  • 使用OpenSSL生成根证书并自签署证书
  • OpenCV入门
  • React组件(二):常见属性和函数
  • React从基础入门到高级实战:React 基础入门 - 简介与开发环境搭建
  • React从基础入门到高级实战:React 基础入门 - 列表渲染与条件渲染
  • 初始Flask框架
  • C++之STL--string
  • 移远三款主流5G模块RM500U,RM520N,RG200U比较
  • 电脑风扇转速不正常的原因
  • Flask框架
  • DeepSeek 赋能智能电网:从技术革新到全场景应用实践
  • Android 直接通过 app_process 启动的应用如何使用 Context
  • 3362. 零数组变换 III
  • PPP 拨号失败:ATD*99***1# ... failed
  • 610Hz!无惧环境光新薄膜!ROG全新电竞显示器亮相2025台北电脑展
  • 第七部分:第二节 - 在 Node.js 中连接和操作 MySQL:厨房与仓库的沟通渠道
  • STM32:深度解析RS-485总线与SP3485芯片
  • QT聊天项目DAY12
  • 科技成果鉴定测试怎么进行?进行鉴定测试有什么好处
  • 精准核验,实时响应-身份证实名认证接口-身份证二要素核验
  • 基于 SpringBoot + Vue 的海滨体育馆管理系统设计与实现
  • Golang基于 Swagger + JWT + RBAC 的认证授权中间件设计