鸿蒙PC Electron跨平台应用开发:24时区时间表应用详解

欢迎加入开源鸿蒙PC社区:

https://harmonypc.csdn.net/

atomgit仓库地址: https://atomgit.com/ai_lingshi/time24

一、项目概述

在全球化时代,跨时区协作已成为日常工作的常态。无论是远程办公、跨国会议还是全球化业务运营,了解不同时区的时间都至关重要。本文将详细介绍如何基于 Electron 运行时开发一款全球24时区时间表应用,该应用可以运行在 HarmonyOS 桌面环境中。

1.1 项目背景

随着远程工作和全球化协作的普及,人们需要一款直观、美观的时区查看工具。传统的时区转换工具往往功能单一、界面简陋,难以满足现代办公需求。本项目旨在打造一款功能丰富、视觉精美的24时区时间表应用。

1.2 功能定位

  • 实时时间显示:全球24个时区的实时时间展示
  • 智能标识:自动识别本地时区并高亮显示
  • 时段标记:区分工作时间和午夜时段
  • 视觉美观:采用现代UI设计风格

1.3 技术架构

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    前端应用层                              │
│    (HTML5 + CSS3 + JavaScript)                            │
│    ┌─────────────┐  ┌─────────────┐  ┌─────────────┐      │
│    │  index.html │  │   style.css │  │    app.js   │      │
│    │  (结构层)   │  │   (样式层)   │  │   (逻辑层)  │      │
│    └─────────────┘  └─────────────┘  └─────────────┘      │
├─────────────────────────────────────────────────────────────┤
│              Electron + Preload 层                         │
│              (IPC 通信、API 暴露)                          │
├─────────────────────────────────────────────────────────────┤
│               HarmonyOS 原生层                             │
│         (libadapter.so + ETS Adapters)                    │
└─────────────────────────────────────────────────────────────┘

二、核心功能实现

2.1 时区数据结构设计

应用的核心是时区数据,我们需要定义包含时区名称、UTC偏移量和代表城市的数据结构:

javascript 复制代码
const timezones = [
    { name: '国际日期变更线', offset: -12, cities: ['中途岛', '萨摩亚'] },
    { name: '萨摩亚标准时间', offset: -11, cities: ['美属萨摩亚'] },
    { name: '夏威夷-阿留申标准时间', offset: -10, cities: ['檀香山'] },
    { name: '阿拉斯加标准时间', offset: -9, cities: ['安克雷奇'] },
    { name: '太平洋标准时间', offset: -8, cities: ['洛杉矶', '旧金山', '西雅图'] },
    { name: '山地标准时间', offset: -7, cities: ['丹佛', '凤凰城'] },
    { name: '中部标准时间', offset: -6, cities: ['芝加哥', '休斯顿', '达拉斯'] },
    { name: '东部标准时间', offset: -5, cities: ['纽约', '华盛顿', '波士顿'] },
    { name: '大西洋标准时间', offset: -4, cities: ['波多黎各', '百慕大'] },
    { name: '南美洲东部时间', offset: -3, cities: ['圣保罗', '布宜诺斯艾利斯'] },
    { name: '南乔治亚时间', offset: -2, cities: ['南乔治亚岛'] },
    { name: '亚速尔群岛时间', offset: -1, cities: ['亚速尔群岛'] },
    { name: '格林威治标准时间', offset: 0, cities: ['伦敦', '都柏林', '里斯本'] },
    { name: '中欧标准时间', offset: 1, cities: ['柏林', '巴黎', '罗马', '马德里'] },
    { name: '东欧标准时间', offset: 2, cities: ['莫斯科', '开罗', '雅典'] },
    { name: '东非标准时间', offset: 3, cities: ['内罗毕', '巴格达', '利雅得'] },
    { name: '阿拉伯标准时间', offset: 4, cities: ['迪拜', '阿布扎比'] },
    { name: '巴基斯坦标准时间', offset: 5, cities: ['伊斯兰堡', '卡拉奇'] },
    { name: '孟加拉国标准时间', offset: 6, cities: ['达卡'] },
    { name: '印度支那时间', offset: 7, cities: ['曼谷', '河内', '雅加达'] },
    { name: '中国标准时间', offset: 8, cities: ['北京', '上海', '香港', '台北'] },
    { name: '日本标准时间', offset: 9, cities: ['东京', '首尔', '大阪'] },
    { name: '澳大利亚东部标准时间', offset: 10, cities: ['悉尼', '墨尔本', '布里斯班'] },
    { name: '新西兰标准时间', offset: 12, cities: ['奥克兰', '惠灵顿'] }
];

设计要点:

  • 覆盖UTC-12到UTC+12的完整时区范围
  • 每个时区包含名称、偏移量和代表城市列表
  • 数据结构简洁清晰,便于扩展和维护

2.2 时间计算核心函数

2.2.1 UTC时间转换函数
javascript 复制代码
function getTimezoneDate(offset) {
    const now = new Date();
    const utc = now.getTime() + now.getTimezoneOffset() * 60000;
    return new Date(utc + offset * 3600000);
}

实现原理:

  1. 获取当前本地时间
  2. 将本地时间转换为UTC时间(通过 getTimezoneOffset() 获取本地时区与UTC的分钟差)
  3. 根据目标时区的偏移量计算目标时区时间
2.2.2 本地时区检测函数
javascript 复制代码
function isLocalTimezone(offset) {
    const localOffset = -new Date().getTimezoneOffset() / 60;
    return offset === localOffset;
}

实现原理:

  • getTimezoneOffset() 返回本地时间与UTC的分钟差(东时区为负,西时区为正)
  • 取负值并除以60得到小时偏移量
  • 与目标时区偏移量比较判断是否为本地时区
2.2.3 时段判断函数
javascript 复制代码
function isWorkingHours(hour) {
    return hour >= 9 && hour < 18;
}

function isPastMidnight(hour) {
    return hour >= 0 && hour < 6;
}

设计逻辑:

  • 工作时间定义为9:00-18:00
  • 午夜时段定义为0:00-6:00
  • 通过简单的小时判断实现时段分类

2.3 动态卡片生成机制

javascript 复制代码
function createTimezoneCard(timezone) {
    const date = getTimezoneDate(timezone.offset);
    const hour = date.getHours();
    const isLocal = isLocalTimezone(timezone.offset);
    const isWorking = isWorkingHours(hour);
    const isNight = isPastMidnight(hour);

    let cardClass = 'timezone-card';
    if (isLocal) cardClass += ' local';
    else if (isNight) cardClass += ' past-midnight';
    else if (isWorking) cardClass += ' working-hours';

    const timeBlocks = getTimeBlocks(hour);

    return `
        <div class="${cardClass}">
            <div class="timezone-info">
                <span class="timezone-name">${timezone.name}</span>
                <span class="timezone-offset">${formatOffset(timezone.offset)}</span>
            </div>
            <div class="time-display">${formatTime(date)}</div>
            <div class="date-display">${formatDate(date)}</div>
            <div class="location-info">
                <i>📍</i>
                <span>${timezone.cities.join(', ')}</span>
            </div>
            <div class="time-indicator">
                ${timeBlocks.map((active, index) => 
                    `<div class="time-block${active ? ' active' : ''}" title="${index}:00"></div>`
                ).join('')}
            </div>
        </div>
    `;
}

核心流程:

步骤 操作 说明
1 获取时区时间 调用 getTimezoneDate() 计算目标时区当前时间
2 判断时段类型 根据小时判断是否为工作时间或午夜时段
3 构建CSS类名 根据本地时区、工作时间、午夜时段添加对应类名
4 生成时间块 创建24小时指示器
5 返回HTML模板 拼接完整的卡片HTML字符串

2.4 实时更新机制

javascript 复制代码
function updateTime() {
    const grid = document.getElementById('timezoneGrid');
    grid.innerHTML = timezones.map(createTimezoneCard).join('');

    const localDate = new Date();
    document.getElementById('localDateTime').textContent = 
        `本地时间: ${formatTime(localDate)} ${formatDate(localDate)}`;
}

updateTime();
setInterval(updateTime, 1000);

实现策略:

  • 初始化时立即执行一次 updateTime()
  • 使用 setInterval() 每秒更新一次时间
  • 更新时重新生成所有时区卡片,确保时间实时同步

三、视觉设计与样式实现

3.1 整体视觉风格

应用采用深色主题设计,配合现代玻璃态效果:

css 复制代码
body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
    min-height: 100vh;
    color: #fff;
}

设计特点:

  • 深蓝到紫色的渐变背景
  • 现代无衬线字体
  • 白色文字确保可读性

3.2 卡片布局设计

css 复制代码
.timezone-card {
    background: rgba(255, 255, 255, 0.05);
    backdrop-filter: blur(10px);
    border-radius: 12px;
    padding: 20px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    transition: all 0.3s ease;
}

.timezone-card:hover {
    transform: translateY(-5px);
    box-shadow: 0 10px 40px rgba(102, 126, 234, 0.2);
    border-color: rgba(102, 126, 234, 0.3);
}

视觉效果:

  • 玻璃态背景(backdrop-filter: blur()
  • 半透明边框
  • 悬停时上浮效果
  • 紫色光晕阴影

3.3 智能标识样式

css 复制代码
.timezone-card.local {
    background: linear-gradient(135deg, rgba(102, 126, 234, 0.2) 0%, rgba(118, 75, 162, 0.2) 100%);
    border-color: rgba(102, 126, 234, 0.5);
}

.timezone-card.past-midnight {
    background: rgba(255, 0, 0, 0.08);
}

.timezone-card.working-hours {
    background: rgba(0, 255, 136, 0.08);
}

标识规则:

状态 样式 含义
.local 紫色渐变背景 用户本地时区
.past-midnight 红色背景 午夜时段(0:00-6:00)
.working-hours 绿色背景 工作时间(9:00-18:00)

3.4 响应式布局

css 复制代码
.timezone-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 20px;
}

@media (max-width: 768px) {
    .header h1 {
        font-size: 1.8rem;
    }

    .time-display {
        font-size: 2.2rem;
    }

    .legend {
        flex-wrap: wrap;
    }
}

响应式策略:

  • 使用 CSS Grid 的 auto-fit 实现自适应列数
  • 移动端缩小标题和时间显示字体
  • 图例区域支持换行

四、核心代码详解

4.1 时间格式化函数

javascript 复制代码
function formatOffset(offset) {
    const sign = offset >= 0 ? '+' : '';
    return `UTC${sign}${offset}`;
}

function formatTime(date) {
    return date.toLocaleTimeString('zh-CN', {
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
        hour12: false
    });
}

function formatDate(date) {
    return date.toLocaleDateString('zh-CN', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        weekday: 'short'
    });
}

技术要点:

  • 使用 toLocaleTimeString() 实现本地化时间格式
  • 指定 zh-CN 确保中文显示
  • hour12: false 强制使用24小时制

4.2 时间块指示器生成

javascript 复制代码
function getTimeBlocks(hour) {
    const blocks = [];
    for (let i = 0; i < 24; i++) {
        blocks.push(i === hour);
    }
    return blocks;
}

实现逻辑:

  • 生成24个布尔值的数组
  • 当前小时对应的位置为 true,其余为 false
  • 在卡片模板中根据布尔值决定是否添加 .active

4.3 索引结构优化

javascript 复制代码
const grid = document.getElementById('timezoneGrid');
grid.innerHTML = timezones.map(createTimezoneCard).join('');

性能优化:

  • 使用 map() 批量生成卡片HTML
  • 使用 join('') 一次性插入DOM
  • 避免多次DOM操作提升性能

五、项目结构与组织

5.1 文件组织结构

复制代码
ohos_hap/web_engine/src/main/resources/resfile/resources/app/
├── main.js          # Electron 主进程配置
├── preload.js       # 桥接脚本
├── index.html       # HTML结构
├── style.css        # 样式定义
└── app.js           # 应用逻辑

5.2 文件职责划分

文件 职责 内容
main.js Electron主进程 窗口创建、菜单配置、IPC通信
preload.js 预加载脚本 暴露原生API给渲染进程
index.html 页面结构 HTML标签、资源引用
style.css 样式定义 布局、颜色、动画
app.js 业务逻辑 时区计算、DOM更新

5.3 代码分离原则

关注点分离(Separation of Concerns):

  1. HTML:负责页面结构,不包含样式和逻辑
  2. CSS:负责视觉表现,不包含业务逻辑
  3. JavaScript:负责交互逻辑,不直接处理样式

六、HarmonyOS原生能力集成

6.1 Electron主进程配置

javascript 复制代码
const { app, BrowserWindow, Menu } = require('electron');
const path = require('path');

let mainWindow;

function createWindow() {
    mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        minWidth: 600,
        minHeight: 500,
        fullscreen: false,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js'),
            nodeIntegration: true,
            contextIsolation: false
        }
    });

    mainWindow.loadFile(path.join(__dirname, 'index.html'));
}

app.whenReady().then(createWindow);

关键配置:

  • 设置窗口初始大小和最小尺寸
  • 禁用全屏模式(fullscreen: false
  • 配置预加载脚本路径

6.2 原生API暴露

通过 preload.js 可以向渲染进程暴露原生能力:

javascript 复制代码
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
    showNotification: (title, body) => {
        ipcRenderer.send('show-notification', title, body);
    },
    getSystemInfo: () => {
        return ipcRenderer.invoke('get-system-info');
    }
});

可用原生能力:

功能 方法 说明
系统信息 getSystemInfo() 获取设备和系统信息
文件对话框 showOpenDialog() 打开文件选择对话框
通知 showNotification() 显示系统通知
窗口控制 window:minimize/maximize/close 窗口操作
剪贴板 clipboard:read/write 剪贴板操作

七、运行与构建

7.1 开发环境要求

  • Node.js 18+
  • DevEco Studio 5.0+
  • HarmonyOS SDK

7.2 运行项目

在 DevEco Studio 中打开项目后:

  1. 配置 HarmonyOS SDK 路径
  2. 选择目标设备或模拟器
  3. 点击运行按钮启动应用

7.3 构建HAP包

bash 复制代码
cd ohos_hap
hvigorw assembleHap

构建产物:

  • entry/build/outputs/hap/debug/entry-debug.hap

八、功能扩展建议

8.1 可能的功能增强

功能 描述 实现难度
时区搜索 支持按名称或城市搜索时区
时区对比 选择多个时区进行对比显示
世界时钟 添加常用时区到快捷面板
日期计算器 计算不同时区的日期差异
夏令时支持 自动识别夏令时调整
会议时间建议 根据多个时区推荐合适会议时间

8.2 性能优化方向

  1. 虚拟滚动:当日时区数量增加时,使用虚拟滚动减少DOM节点
  2. 缓存机制:缓存计算结果避免重复计算
  3. Web Worker:将时间计算移到Web Worker避免阻塞主线程

8.3 国际化支持

  • 支持多语言切换
  • 时区名称本地化
  • 日期格式本地化

九、常见问题与解决方案

9.1 时间显示不正确

问题描述:某个时区的时间显示与实际不符

排查步骤

步骤 检查项 说明
1 系统时区设置 确认系统时区是否正确
2 偏移量计算 检查 getTimezoneDate() 函数
3 夏令时影响 某些时区存在夏令时调整
4 Date对象使用 确保使用正确的Date方法

解决方案

javascript 复制代码
// 确保使用UTC时间计算
function getTimezoneDate(offset) {
    const now = new Date();
    const utc = now.getTime() + now.getTimezoneOffset() * 60000;
    return new Date(utc + offset * 3600000);
}

9.2 构建失败

问题描述 :执行 hvigorw assembleHap 时报错

常见原因

错误类型 原因 解决方案
签名配置错误 bundleName不匹配 检查 app.json5 和签名配置
资源缺失 字符串资源未定义 检查 string.json
依赖问题 Node.js版本不兼容 使用Node.js 18+

9.3 窗口显示问题

问题描述:窗口无法正常显示或尺寸异常

检查项

  • main.js 中窗口配置是否正确
  • 确保 fullscreen: false
  • 检查 minWidthminHeight 设置

十、总结

10.1 项目成果

本文详细介绍了基于 Electron 运行时的24时区时间表应用开发过程,涵盖了:

  1. 核心功能实现:时区数据结构、时间计算、动态卡片生成、实时更新
  2. 视觉设计:深色主题、玻璃态效果、智能标识、响应式布局
  3. 架构设计:关注点分离、文件组织、原生能力集成

10.2 技术亮点

  • 实时时间同步:每秒更新确保时间准确性
  • 智能标识系统:自动识别本地时区和时段类型
  • 现代UI设计:玻璃态效果和流畅动画
  • 跨平台兼容:基于Electron支持多平台运行

10.3 未来展望

该应用可以进一步扩展功能,如添加时区搜索、会议时间建议、夏令时支持等,使其成为一款功能完善的全球化办公工具。同时,可以通过性能优化提升应用响应速度,通过国际化支持服务全球用户。


项目地址https://github.com/example/timezone-app

技术栈:HTML5 + CSS3 + JavaScript + Electron + HarmonyOS

License:MIT

相关推荐
字节跳动开源1 小时前
你的 Agent 每次都“失忆”?这个工具彻底治好了我的前端开发焦虑
大数据·开源·agent
Electrolux2 小时前
[onlyoffice-v9]纯前端怎么实现编辑预览office
前端·javascript·github
码云之上2 小时前
聊聊如何设计一个高效、稳定的 Node.js 接入层
前端·后端·node.js
kyriewen2 小时前
我读了一遍 Babel 编译后的 async/await,终于搞懂了它的原理(附 20 行手写实现)
前端·javascript·面试
IT_陈寒3 小时前
Vite项目build后路由404了?你可能漏了这个小配置
前端·人工智能·后端
lichenyang4533 小时前
AI 聊天从纯文本到结构化卡片:SSE done 帧携带 card + 历史记录卡片恢复实战
前端
梦曦i4 小时前
@meng-xi/vite-plugin v0.1.5:告别手动 import,精简工具层
前端
梦曦i4 小时前
Vite 0.1.6重磅更新:智能导入+路由安全
前端
gxf5203088069884 小时前
Flutter 裁剪图片
前端·app