哈喽,大家好!我是油柑,本次带来的是Electron实现简易番茄钟,包括倒计时结束铃声,切换主题,记录任务数等
代码:
1、index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>油柑 番茄钟</title>
<link rel="stylesheet" href="dark-theme.css" id="theme">
</head>
<body>
<div class="container">
<div class="timer">
<h1 id="timer">00:00:00</h1>
<select id="hours">
<option value="1">1 小时</option>
<option value="2">2 小时</option>
<option value="3">3 小时</option>
<option value="4">4 小时</option>
<option value="5">5 小时</option>
</select>
<div class="buttons">
<button id="start">开始</button>
<button id="reset">重置</button>
<button id="toggleTheme">切换主题</button>
</div>
<ul id="tasks">
</ul>
<div class="task-input">
<input type="text" id="taskInput" placeholder="添加任务">
<button id="addTask">添加</button>
</div>
<audio id="audio" src="bell.mp3"></audio>
</div>
<div class="statistics">
<h2>统计</h2>
<p>共完成多少任务: <span id="tomatoCount">0</span></p>
<p>总共花费的时间: (hours): <span id="totalTime">0</span></p>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
2、main.js(入口文件)
// 我们需要导入两个electron模块
const { app, BrowserWindow } = require('electron')
// 创建一个createWindow()函数,用于将index.html加载到新BrowserWindow实例中
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
let promise = win.loadFile('index.html');
}
// 调用这个createWindow()函数来打开你的窗口
app.whenReady().then(() => {
createWindow()
})
3、app.js文件
let timer;
let maxTasks = 3;
let tomatoCount = 0;
let totalTime = 0;
let isDarkTheme = true;
document.getElementById('start').addEventListener('click', startTimer);
document.getElementById('reset').addEventListener('click', resetTimer);
document.getElementById('addTask').addEventListener('click', addTask);
document.getElementById('toggleTheme').addEventListener('click', toggleTheme);
function startTimer() {
let hoursInput = document.getElementById('hours').value;
let hours = parseInt(hoursInput);
if (isNaN(hours) || hours <= 0) {
alert("Please select a valid number of hours.");
return;
}
let totalSeconds = hours * 60 * 60;
startCountdown(totalSeconds);
}
function startCountdown(totalSeconds) {
clearInterval(timer);
timer = setInterval(function() {
if (totalSeconds === 0) {
clearInterval(timer);
document.getElementById('timer').innerText = 'Time\'s up!';
document.getElementById('audio').play();
showNotification("Time's up!", "Your task is complete.");
tomatoCount++;
totalTime += parseInt(document.getElementById('hours').value);
updateStatistics();
return;
}
let hours = Math.floor(totalSeconds / 3600);
let minutes = Math.floor((totalSeconds % 3600) / 60);
let seconds = totalSeconds % 60;
document.getElementById('timer').innerText = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
if (totalSeconds === 300) {
showNotification("5 minutes left", "Finish up your task!");
}
totalSeconds--;
}, 1000);
}
function resetTimer() {
clearInterval(timer);
document.getElementById('timer').innerText = '00:00:00';
}
function addTask() {
let taskInput = document.getElementById('taskInput').value.trim();
if (taskInput === "") {
alert("Please enter a task.");
return;
}
let taskList = document.getElementById('tasks');
if (taskList.children.length >= maxTasks) {
alert("你只能添加三个任务");
return;
}
let taskItem = document.createElement('li');
taskItem.textContent = taskInput;
taskList.appendChild(taskItem);
let deleteButton = document.createElement('button');
deleteButton.textContent = '删除';
deleteButton.className = 'deleteTask';
taskItem.appendChild(deleteButton);
document.getElementById('taskInput').value = "";
}
document.addEventListener('click', function(event) {
if (event.target.classList.contains('deleteTask')) {
event.target.parentNode.remove();
}
});
function showNotification(title, message) {
if (!("Notification" in window)) {
alert("This browser does not support desktop notification");
} else if (Notification.permission === "granted") {
new Notification(title, { body: message });
} else if (Notification.permission !== "denied") {
Notification.requestPermission().then(function (permission) {
if (permission === "granted") {
new Notification(title, { body: message });
}
});
}
}
function updateStatistics() {
document.getElementById('tomatoCount').innerText = tomatoCount;
document.getElementById('totalTime').innerText = totalTime;
}
function toggleTheme() {
const themeLink = document.getElementById('theme');
if (isDarkTheme) {
themeLink.href = 'light-theme.css';
isDarkTheme = false;
} else {
themeLink.href = 'dark-theme.css';
isDarkTheme = true;
}
}
4、样式文件(两个)
body {
font-family: Arial, sans-serif;
background-color: #000;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.container {
max-width: 600px;
padding: 20px;
background-color: #333;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
display: flex;
justify-content: space-between;
}
.timer {
text-align: center;
}
.timer img {
margin-bottom: 20px;
}
.timer h1 {
font-size: 3rem;
}
select {
padding: 10px;
margin: 10px;
font-size: 1rem;
border: none;
border-radius: 5px;
cursor: pointer;
}
.buttons {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
button {
padding: 10px 20px;
margin: 0 10px;
font-size: 1rem;
border: none;
border-radius: 5px;
cursor: pointer;
background-color: #007bff;
color: #fff;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #0056b3;
}
ul {
list-style-type: none;
padding: 0;
margin-bottom: 20px;
}
li {
margin-bottom: 5px;
display: flex;
align-items: center;
}
.deleteTask {
margin-left: auto;
}
.task-input {
display: flex;
justify-content: center;
align-items: center;
}
.task-input input[type="text"] {
flex: 1;
padding: 10px;
font-size: 1rem;
border: 1px solid #ddd;
border-radius: 5px 0 0 5px;
border-right: none;
background-color: #fff;
color: #000;
}
.task-input button {
padding: 10px 20px;
font-size: 1rem;
border: none;
border-radius: 0 5px 5px 0;
cursor: pointer;
background-color: #007bff;
color: #fff;
transition: background-color 0.3s ease;
}
.task-input button:hover {
background-color: #0056b3;
}
.statistics {
flex: 1;
padding: 20px;
}
.statistics h2 {
font-size: 1.5rem;
margin-bottom: 10px;
}
.statistics p {
font-size: 1rem;
margin-bottom: 5px;
}
body {
font-family: Arial, sans-serif;
background-color: #fff;
color: #000;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.container {
max-width: 600px;
padding: 20px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
display: flex;
justify-content: space-between;
}
.timer {
text-align: center;
}
.timer img {
margin-bottom: 20px;
}
.timer h1 {
font-size: 3rem;
}
select {
padding: 10px;
margin: 10px;
font-size: 1rem;
border: none;
border-radius: 5px;
cursor: pointer;
}
.buttons {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
button {
padding: 10px 20px;
margin: 0 10px;
font-size: 1rem;
border: none;
border-radius: 5px;
cursor: pointer;
background-color: #007bff;
color: #fff;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #0056b3;
}
ul {
list-style-type: none;
padding: 0;
margin-bottom: 20px;
}
li {
margin-bottom: 5px;
display: flex;
align-items: center;
}
.deleteTask {
margin-left: auto;
}
.task-input {
display: flex;
justify-content: center;
align-items: center;
}
.task-input input[type="text"] {
flex: 1;
padding: 10px;
font-size: 1rem;
border: 1px solid #ddd;
border-radius: 5px 0 0 5px;
border-right: none;
background-color: #fff;
color: #000;
}
.task-input button {
padding: 10px 20px;
font-size: 1rem;
border: none;
border-radius: 0 5px 5px 0;
cursor: pointer;
background-color: #007bff;
color: #fff;
transition: background-color 0.3s ease;
}
.task-input button:hover {
background-color: #0056b3;
}
.statistics {
flex: 1;
padding: 20px;
}
.statistics h2 {
font-size: 1.5rem;
margin-bottom: 10px;
}
.statistics p {
font-size: 1rem;
margin-bottom: 5px;
}
那么,本次分享就到这啦,我们下次再见!
代码下载地址:基于Electron实现简易番茄钟: 本次使用Electron实现简易番茄钟,包括倒计时结束铃声,切换主题,记录任务数等 (gitee.com)