小程序实现一个 倒计时组件

小程序实现一个 倒计时组件

需求背景

  • 要做一个倒计时,可能是天级别,也可能是日级别,时级别,而且每个有效订单都要用,就做成组件了

效果图

需求分析

  1. 需要一个未来的时间戳,或者在服务度直接下发一个未来到现在时间差,我们只需要做倒计时
  2. 进入页面,看是否已经结束, 如果没结束就调用倒计时函数
  3. 每隔1000,做时间戳(毫秒) -1000。边做tick ,边做时间格式化。
  4. 每次调用前,先清除上一个定时器
  5. 组件销毁的时候,也要清除一下定时器

代码实现

  1. 设置初始值,也是1秒,这里单位时毫秒
js 复制代码
const interval = 1000;
  1. 进入页面,初始化完成。开始判断是否结束
js 复制代码
lifetimes: {
		ready() {
			this.startCountdown();
		},
		detached() {
			clearTimeout(this.timer);
		},
	},
js 复制代码
startCountdown() {
    const lastTime = this.initTime(this.properties.expireTime); // 这一步,如果服务端返回了未来到现在的差值,则不需要自己计算时间差了
    // 如果最终时间 < 1000ms 说明 已经过期了,就不用展示倒计时了.
    if (lastTime > interval) {
    // 格式化要展示的数据
    this.defaultFormat(lastTime);
    this.setData({
            isCountOver: true, // 标识可以显示倒计时
            lastTime, // set lastTime
    });
    // 调用倒计时函数,主要的逻辑就是每隔1000ms ,让lastTime - 1000
        this.tick();
        }
    },

初始化时间: 如果服务度返回了时间差,这一步不用处理

js 复制代码
//初始化时间
initTime(expireTime) {
    let lastTime = Number(new Date(expireTime * 1000)) - new Date().getTime();
    console.log('lastTime', lastTime);
    return Math.max(lastTime, 0);
},

时间的格式化处理,这里都是固定代码,没什么含量

js 复制代码
//默认处理时间格式
defaultFormat(time) {
    const days = 60 * 60 * 1000 * 24;
    const hours = 60 * 60 * 1000;
    const minutes = 60 * 1000;
    const d = Math.floor(time / days);
    const h = Math.floor((time % days) / hours);

    const m = Math.floor((time % hours) / minutes);
    const s = Math.floor((time % minutes) / 1000);

    this.setData({
            d: this.fixedZero(d),
            h: this.fixedZero(h),
            m: this.fixedZero(m),
            s: this.fixedZero(s),
    });
},
// 格式化时间加0
fixedZero(val) {
        return val < 10 ? `0${val}` : val;
},

tick 倒计时函数

js 复制代码
tick() {
    let { lastTime } = this.data;
    this.timer = setTimeout(() => {
    // 每次定时器之前,先把上一个定时器清除
        clearTimeout(this.timer);
    // 如果倒计时结束,这是结束的状态
            if (lastTime < interval) {
                    this.setData({
                            lastTime: 0,
                            isCountOver: false,
                    });
            } else {
    // 如果倒计时正常,则每次 -1000 ,并且格式化时间。再次调用tick,直到倒计时结束
                    lastTime -= 1000;
                    this.setData(
                            {
                                    lastTime,
                            },
                            () => {
                                    this.defaultFormat(lastTime);
                                    this.tick();
                            },
                    );
            }
    }, interval);
    },

完整代码

  • 父组件(我这里传了一个比较大的时间戳,2024,10.1结束的时间戳)
js 复制代码
<order-time expireTime="{{ 1727712000 }}">
    <view slot="desc">还剩</view>
</order-time>
  • 子组件 (wxml)
js 复制代码
<view wx:if="{{ isCountOver }}" class="timer-wrap">
	<slot name="desc" />
	<view class="reset-time">
		<text wx:if="{{ d != '00' }}"> {{ d }}天</text>
		{{ h }}:{{ m }}:{{ s }}</view
	>
</view>
<view wx:else class="reset-time"> {{ emptyType === '1' ? '已超时': '' }} </view>
  • 子组件 (js)
js 复制代码
let interval = 1000;
Component({
	options: {
		multipleSlots: true,
	},
	properties: {
		expireTime: {
			type: String,
		},
		emptyType: {
			type: String,
			value: '1',
		},
	},

	lifetimes: {
		ready() {
			this.startCountdown();
		},
		detached() {
			clearTimeout(this.timer);
		},
	},

	/**
	 * 组件的初始数据
	 */
	data: {
		d: 0, //天
		h: 0, //时
		m: 0, //分
		s: 0, //秒
		lastTime: '', //倒计时的时间戳
		isCountOver: false, // 倒计时是否完成
	},

	/**
	 * 组件的方法列表
	 */
	methods: {
		startCountdown() {
			const lastTime = this.initTime(this.properties.expireTime);

			if (lastTime > interval) {
				this.defaultFormat(lastTime);
				this.setData({
					isCountOver: true,
					lastTime,
				});

				this.tick();
			}
		},
		//默认处理时间格式
		defaultFormat(time) {
			const days = 60 * 60 * 1000 * 24;
			const hours = 60 * 60 * 1000;
			const minutes = 60 * 1000;
			const d = Math.floor(time / days);
			const h = Math.floor((time % days) / hours);

			const m = Math.floor((time % hours) / minutes);
			const s = Math.floor((time % minutes) / 1000);

			this.setData({
				d: this.fixedZero(d),
				h: this.fixedZero(h),
				m: this.fixedZero(m),
				s: this.fixedZero(s),
			});
		},

		//定时事件
		tick() {
			let { lastTime } = this.data;
			this.timer = setTimeout(() => {
				clearTimeout(this.timer);
				if (lastTime < interval) {
					this.setData({
						lastTime: 0,
						isCountOver: false,
					});
				} else {
					lastTime -= 1000;
					this.setData(
						{
							lastTime,
						},
						() => {
							this.defaultFormat(lastTime);
							this.tick();
						},
					);
				}
			}, interval);
		},

		//初始化时间
		initTime(expireTime) {
			let lastTime = Number(new Date(expireTime * 1000)) - new Date().getTime();
			console.log('lastTime', lastTime);
			return Math.max(lastTime, 0);
		},

		// 格式化时间加0
		fixedZero(val) {
			return val < 10 ? `0${val}` : val;
		},
	},
});
  • 遇到相关变量,自己更改即可

End: 写作粗陋,有纰漏,建议之处,多多指教~~~

相关推荐
程序员大金2 小时前
基于SpringBoot+Vue+MySQL的装修公司管理系统
vue.js·spring boot·mysql
道爷我悟了3 小时前
Vue入门-指令学习-v-html
vue.js·学习·html
无咎.lsy3 小时前
vue之vuex的使用及举例
前端·javascript·vue.js
工业互联网专业3 小时前
毕业设计选题:基于ssm+vue+uniapp的校园水电费管理小程序
vue.js·小程序·uni-app·毕业设计·ssm·源码·课程设计
计算机学姐4 小时前
基于SpringBoot+Vue的在线投票系统
java·vue.js·spring boot·后端·学习·intellij-idea·mybatis
twins35205 小时前
解决Vue应用中遇到路由刷新后出现 404 错误
前端·javascript·vue.js
qiyi.sky5 小时前
JavaWeb——Vue组件库Element(3/6):常见组件:Dialog对话框、Form表单(介绍、使用、实际效果)
前端·javascript·vue.js
杨荧6 小时前
【JAVA开源】基于Vue和SpringBoot的洗衣店订单管理系统
java·开发语言·vue.js·spring boot·spring cloud·开源
Front思6 小时前
vue使用高德地图
javascript·vue.js·ecmascript
说私域7 小时前
社群团购中的用户黏性价值:以开源小程序多商户AI智能名片商城源码为例
人工智能·小程序