实验目的
- 掌握小程序定时器 API:
setTimeout()、setInterval()、clearInterval()的使用。 - 理解页面延迟渲染、倒计时逻辑,实现开始、停止、继续、重新倒计时业务逻辑。
- 掌握
hidden条件渲染、数据绑定setData()页面更新数据。 - 掌握 CSS 层叠定位,实现背景水印文字效果;了解小程序 WXSS 不支持 CSS 伪元素
::before的坑点,使用双层view替代伪元素完成叠加文字。
实验环境
- 开发工具:微信开发者工具
- 项目模式:不使用云服务、不使用模板,渲染引擎
renderer:webview - 编程语言:WXML + WXSS + JavaScript
实验需求
- 小程序启动,初始页面空白,延迟 2 秒之后展示计时器界面。
- 倒计时初始数值为 60。
- 点击【开始计时】启动倒计时;点击【停止计时】暂停;未到 0 时再次点击开始,可以继续倒计时。
- 倒计时到 0 之后,点击开始、停止按钮不再产生计时效果。
- 点击【重新计时】,重置数字回到 60,自动开始倒计时。
- 扩展功能:计时数字框内部增加半透明背景文字:逝者如斯夫,不舍昼夜,文字置于数字底层。
实现思路
- 2 秒延迟显示界面:页面
onLoad生命周期,调用setTimeout延迟 2000ms,修改hidden,让计时盒子显示。 - 倒计时控制
setInterval():周期定时器,每 1000ms 执行一次,实现数字每秒减一。clearInterval():关闭周期定时器,实现暂停计时。- 全局变量
num保存倒计时数字;isTime布尔标记,控制是否允许计时;timerId保存定时器编号,用于关闭定时器。
- 边界判断:当
num===0,清除定时器,设置isTime=false,禁止继续计时。 - 重置逻辑:
restart()清除旧定时器,重置num=60、恢复isTime=true,调用 start 开启计时。 - 背景文字扩展:小程序 WXSS 不支持
::before伪元素,使用两层 view。外层设置position:relative作为定位容器;内层背景文字设置position:absolute居中,z‑index:1;数字层z‑index:2浮于上方,实现水印叠加。
核心代码片段
index.wxml
<!--index.wxml--> <navigation-bar title="计时器" back="{{false}}" color="black" background="#FFF"></navigation-bar> <scroll-view class="scrollarea" scroll-y type="list"> <view class="box" hidden="{{hidden}}"> <view class="title">计时器函数的应用</view> <view class="time"> <!--背景文字层--> <view class="bg-text">逝者如斯夫,不舍昼夜</view> <!--倒计时数字层--> <view class="num-text">{{num}}</view> </view> <view class="btn-layout"> <button type="primary" size="mini" bind:tap="start">开始计时</button> <button type="primary" size="mini" bind:tap="stop">停止计时</button> <button type="primary" size="mini" bind:tap="restart">重新计时</button> </view> </view> </scroll-view>index.wxss
/**index.wxss**/ page { height: 100vh; display: flex; flex-direction: column; } .scrollarea { flex: 1; overflow-y: hidden; } .time { width: 90%; background-color: blue; color: yellow; font-size: 200rpx; text-align: center; border: 2rpx solid red; border-radius: 60rpx; margin: 30rpx; position: relative; overflow:hidden; } .bg-text{ position:absolute; width:100%; top:50%; transform: translateY(-50%); font-size:40rpx; color:#cccccc; z-index:1; } .num-text{ position:relative; z-index:2; } .btn-layout { display: flex; flex-direction: row; }index.js
// index.js let num = 60 let isTime = true let timerId Page({ data: { hidden: true, num }, onLoad() { // 延迟2秒显示页面 setTimeout(() => { this.show() }, 2000) }, show() { this.setData({ hidden: false }) }, // 开始计时 start() { if (isTime) { timerId = setInterval(() => { this.timer() }, 1000) } }, timer() { this.setData({ num }) if (num > 0) { num-- } else { clearInterval(timerId) isTime = false } }, // 停止计时 stop() { clearInterval(timerId) isTime = true }, //重新计时 restart() { clearInterval(timerId) isTime = true num = 60 this.setData({ num }) this.start() } })app.wxss
/**app.wxss**/ .box { margin: 20rpx; padding: 20rpx; border: 2rpx solid purple; } .title { font-size: 40rpx; font-weight: bold; text-align: center; margin-bottom: 30rpx; color: pink; }app.json
{ "pages": [ "pages/index/index" ], "window": { "navigationBarTextStyle": "black", "navigationStyle": "custom" }, "style": "v2", "renderer": "webview", "componentFramework": "glass-easel", "sitemapLocation": "sitemap.json", "lazyCodeLoading": "requiredComponents" }运行效果
- 小程序刚打开,界面空白,等待 2 秒,蓝色计时框、按钮、标题出现。蓝色方框内部灰色背景文字 “逝者如斯夫,不舍昼夜”,上层黄色数字 60。
- 点击【开始计时】,数字每秒递减。
- 点击【停止计时】数字暂停;再次点击【开始计时】继续往下倒计时。
- 数字归 0,此时点击开始、停止按钮,数字保持 0,不会继续变化。
- 点击【重新计时】,数字立刻回到 60,自动开启倒计时。
遇到的问题与解决
问题:直接使用 CSS 伪元素
.time::before实现背景文字,开发者工具出现黄色警告,伪元素不生效。 原因:微信小程序 WXSS 不完全支持::before、::after伪元素。 解决方案:放弃伪元素,使用双层view,依靠position绝对定位 +z-index层级控制,实现文字叠加效果,消除警告,功能效果一致。
问题:倒计时结束后,还能继续计时。 解决:设置布尔变量
isTime作为开关;倒计时等于 0 时,把isTime设置为 false,start()函数判断isTime,条件不成立就不会新建定时器。
问题:多次点击开始计时,计时变快。 解决:停止、重新计时操作优先执行
clearInterval(timerId)清除旧定时器,避免同时存在多个定时器同时执行。
实验总结
setTimeout只执行一次,适合做延迟显示;setInterval循环执行,适合倒计时、轮播。定时器一定要保存 id,使用clearInterval手动清除,否则定时器会在后台持续运行造成内存问题。- 小程序修改页面显示数据,必须调用
setData(),直接修改 js 变量不会更新视图。 - 定位布局:父容器
position:relative,子元素position:absolute,子元素相对于父盒子进行定位;z-index 控制元素上下层级。 - 开发小程序,要留意 WXSS 和普通 CSS 差异,部分 CSS 特性不能直接使用,需要用标签布局替代。
- 做倒计时业务,需要做好状态标记(isTime),处理边界条件(倒计时到 0),每次开启新定时器前清除旧定时器,防止多个定时器冲突。