利用vue3編寫一個(gè)有趣的牛馬時(shí)鐘并集成到小程序
我最近做了一個(gè)小工具,叫「牛馬時(shí)鐘」,已經(jīng)上線微信小程序了。今天想和大家分享這個(gè)項(xiàng)目的來(lái)龍去脈,以及開(kāi)發(fā)過(guò)程中的一些技術(shù)細(xì)節(jié)。
一、問(wèn)題的起點(diǎn):打工人的時(shí)間困惑
每天上班,我總會(huì)想一個(gè)問(wèn)題:我的時(shí)間到底值多少錢?
月薪 1 萬(wàn),每天工作 8 小時(shí),一個(gè)月 22 個(gè)工作日——數(shù)學(xué)好的人可以立刻算出時(shí)薪:10000/(22×8)≈56.8 元/小時(shí)。但問(wèn)題是,這個(gè)數(shù)字只是靜態(tài)的。當(dāng)我實(shí)際
坐在工位上時(shí),時(shí)間的流逝是動(dòng)態(tài)的:每過(guò) 1 分鐘,我賺了 0.95 元;每刷 10 分鐘手機(jī),就“虧”了 9.5 元。
我需要一個(gè)工具,能實(shí)時(shí)顯示時(shí)間與收益的關(guān)系,讓“摸魚的代價(jià)”變得肉眼可見(jiàn)。這就是「牛馬時(shí)鐘」的核心需求。
二、功能設(shè)計(jì):從需求到落地
工具的功能很簡(jiǎn)單,分兩步:
1. 輸入基礎(chǔ)數(shù)據(jù):月薪、每日工時(shí)、當(dāng)月工作日數(shù)(比如 22 天)。
2. 實(shí)時(shí)計(jì)時(shí):?jiǎn)?dòng)后,頁(yè)面會(huì)顯示已工作時(shí)間(時(shí):分:秒)和累計(jì)收益(精確到分)。
舉個(gè)例子:輸入月薪 8800 元、每日 8 小時(shí)、22 天工作日,時(shí)薪就是 50 元/小時(shí)。工作 1 小時(shí) 15 分鐘,收益就是 50 + (15/60)×50 = 62.5 元。
為了讓用戶不用重復(fù)輸入,數(shù)據(jù)需要本地持久化——下次打開(kāi)小程序時(shí),自動(dòng)讀取上次的輸入。
三、技術(shù)選型:Vue3 + uni-app 的組合
我選擇 Vue3 作為前端框架,主要是因?yàn)樗?strong>組合式 API(Composition API)。相比 Vue2 的選項(xiàng)式 API,組合式 API 更適合邏輯復(fù)用和代碼組織。比如,計(jì)時(shí)器、數(shù)據(jù)計(jì)算這些獨(dú)立功能,可以封裝成獨(dú)立的 composables,代碼結(jié)構(gòu)更清晰。
跨平臺(tái)方面,我用了 uni-app。它能將 Vue 代碼編譯成微信小程序、H5 等多端代碼,一次開(kāi)發(fā)多端運(yùn)行,非常適合這種輕量級(jí)工具。


四、核心代碼實(shí)現(xiàn):用 Vue3 寫計(jì)時(shí)器
1. 基礎(chǔ)數(shù)據(jù)與響應(yīng)式
首先定義輸入數(shù)據(jù)的響應(yīng)式變量。Vue3 的 ref 可以創(chuàng)建響應(yīng)式數(shù)據(jù),computed 可以定義計(jì)算屬性。
// 使用組合式 API,在 setup 函數(shù)中定義
import { ref, computed, onMounted, onUnmounted } from'vue';
exportdefault {
setup() {
// 輸入數(shù)據(jù):月薪、每日工時(shí)、工作日數(shù)
const monthlySalary = ref(null);
const hoursPerDay = ref(null);
const workDays = ref(null);
// 計(jì)算時(shí)薪:月薪 / (工作日數(shù) × 每日工時(shí))
const hourlyWage = computed(() => {
if (!monthlySalary.value || !hoursPerDay.value || !workDays.value) return0;
return (monthlySalary.value / (workDays.value * hoursPerDay.value)).toFixed(2);
});
return { monthlySalary, hoursPerDay, workDays, hourlyWage };
}
};
這里有個(gè)細(xì)節(jié):hourlyWage 用 computed 定義,意味著當(dāng)輸入數(shù)據(jù)變化時(shí),它會(huì)自動(dòng)重新計(jì)算,無(wú)需手動(dòng)調(diào)用。這就是響應(yīng)式的魅力。
2. 計(jì)時(shí)器的實(shí)現(xiàn)
計(jì)時(shí)器需要精確到秒,同時(shí)要避免內(nèi)存泄漏(比如組件卸載時(shí)忘記清除定時(shí)器)。Vue3 的生命周期鉤子 onMounted 和 onUnmounted 可以解決這個(gè)問(wèn)題。
// 在 setup 函數(shù)中繼續(xù)添加
const seconds = ref(0); // 已工作秒數(shù)
let timer = null; // 定時(shí)器引用
// 啟動(dòng)計(jì)時(shí)
const startTimer = () => {
if (timer) return; // 避免重復(fù)啟動(dòng)
timer = setInterval(() => {
seconds.value++;
}, 1000);
};
// 停止計(jì)時(shí)(可選功能)
const stopTimer = () => {
if (timer) {
clearInterval(timer);
timer = null;
}
};
// 組件卸載時(shí)清除定時(shí)器
onUnmounted(() => {
stopTimer();
});
// 計(jì)算已工作時(shí)間(格式化為 HH:MM:SS)
const formattedTime = computed(() => {
const hours = Math.floor(seconds.value / 3600);
const minutes = Math.floor((seconds.value % 3600) / 60);
const secs = seconds.value % 60;
return`${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
});
// 計(jì)算累計(jì)收益
const totalEarnings = computed(() => {
if (!hourlyWage.value) return'0.00';
const earnings = (seconds.value / 3600) * hourlyWage.value;
return earnings.toFixed(2);
});
這段代碼的關(guān)鍵是:
- 用
ref跟蹤秒數(shù),定時(shí)器每秒遞增seconds.value; - 用
computed實(shí)時(shí)格式化時(shí)間和計(jì)算收益; - 用
onUnmounted清除定時(shí)器,避免組件卸載后定時(shí)器仍在運(yùn)行(內(nèi)存泄漏)。
3. 數(shù)據(jù)持久化:uni-app 的本地存儲(chǔ)
為了讓用戶下次打開(kāi)小程序時(shí)能自動(dòng)讀取上次的輸入,需要用到 uni-app 的 uni.setStorageSync 和 uni.getStorageSync(類似瀏覽器的 localStorage)。
// 在 setup 函數(shù)中添加
// 加載緩存數(shù)據(jù)(組件掛載時(shí))
onMounted(() => {
const savedData = uni.getStorageSync('clockConfig');
if (savedData) {
monthlySalary.value = savedData.monthlySalary;
hoursPerDay.value = savedData.hoursPerDay;
workDays.value = savedData.workDays;
}
});
// 保存數(shù)據(jù)(輸入變化時(shí))
constsaveConfig = () => {
if (monthlySalary.value && hoursPerDay.value && workDays.value) {
uni.setStorageSync('clockConfig', {
monthlySalary: monthlySalary.value,
hoursPerDay: hoursPerDay.value,
workDays: workDays.value
});
}
};
// 在模板中,輸入框的 @change 事件綁定 saveConfig
這樣,用戶每次修改輸入后,數(shù)據(jù)會(huì)自動(dòng)保存到本地;下次打開(kāi)小程序時(shí),會(huì)自動(dòng)加載。
五、小程序集成:從 Vue 到小程序的適配
uni-app 的優(yōu)勢(shì)在于“一次編碼,多端運(yùn)行”,但小程序有一些特有的限制,需要注意:
1. 樣式隔離:小程序的 wxss 不支持 scoped(類似 Vue 的樣式作用域),但 uni-app 會(huì)自動(dòng)處理,只需在 Vue 組件中使用 <style scoped> 即可。
2. API 替換:uni-app 封裝了跨平臺(tái) API(如 uni.navigateTo),編譯到小程序時(shí)會(huì)自動(dòng)轉(zhuǎn)換為 wx.navigateTo,無(wú)需額外處理。
3. 性能優(yōu)化:小程序?qū)?yè)面渲染性能要求較高,計(jì)時(shí)器的更新要避免頻繁觸發(fā)重繪。這里用 ref 而非 reactive,因?yàn)?nbsp;ref 對(duì)基本類型(如數(shù)字)的響應(yīng)式更高效。
六、上線后的反饋:工具的價(jià)值超出預(yù)期
上線一周,用戶的反饋?zhàn)屛液芤馔猓?/p>
- 有自由職業(yè)者用它記錄項(xiàng)目耗時(shí),計(jì)算每單實(shí)際收益;
- 有學(xué)生用它監(jiān)督兼職時(shí)長(zhǎng),避免被克扣工資;
- 甚至有寶媽用它記錄“帶娃工時(shí)”,調(diào)侃自己是“月薪 3 萬(wàn)的家庭 CEO”。
到此這篇關(guān)于利用vue3編寫一個(gè)有趣的牛馬時(shí)鐘并集成到小程序的文章就介紹到這了,更多相關(guān)vue3時(shí)鐘內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue+Element-ui表單resetFields無(wú)法重置問(wèn)題
本文主要介紹了Vue+Element-ui表單resetFields無(wú)法重置問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
vue-cli3.0如何使用prerender-spa-plugin插件預(yù)渲染
這篇文章主要介紹了vue-cli3.0如何使用prerender-spa-plugin插件預(yù)渲染,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
詳解Vue項(xiàng)目中如何解決組件之間的循環(huán)依賴
在大型?Vue?項(xiàng)目中,組件之間的關(guān)系可能會(huì)變得非常復(fù)雜,甚至?xí)霈F(xiàn)循環(huán)依賴的問(wèn)題,本文將通過(guò)通俗易懂的方式,講解如何在?Vue?中解決組件之間的循環(huán)依賴問(wèn)題,希望對(duì)大家有所幫助2024-11-11
Spring Boot/VUE中路由傳遞參數(shù)的實(shí)現(xiàn)代碼
在路由時(shí)傳遞參數(shù),一般有兩種形式,一種是拼接在url地址中,另一種是查詢參數(shù)。這篇文章主要介紹了Spring Boot/VUE中路由傳遞參數(shù),需要的朋友可以參考下2018-03-03
Vue 3 中使用 Element Plus 的 `el-t
在 Vue 3 中使用 Element Plus 的 `el-table` 組件實(shí)現(xiàn)自適應(yīng)高度,你可以根據(jù)容器的高度動(dòng)態(tài)設(shè)置表格的高度,下面通過(guò)示例代碼給大家展示,感興趣的朋友一起看看吧2024-12-12
Vue中瀑布流布局與圖片加載優(yōu)化的實(shí)現(xiàn)
本文主要介紹了Vue中瀑布流布局與圖片加載優(yōu)化的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
Vue下路由History模式打包后頁(yè)面空白的解決方法
這篇文章主要介紹了Vue下路由History模式打包后頁(yè)面空白,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06

