
项目介绍
这是一个基于Electron for鸿蒙PC封装步骤进度指示器组件,专为多步骤流程场景设计,如表单提交、流程向导、安装步骤等。该组件提供直观的进度可视化功能,支持灵活的布局配置和动态状态管理,帮助用户清晰了解当前所处流程位置及整体进度。
功能特点
- 布局灵活:支持水平和垂直两种布局模式,适配不同场景的空间需求
- 状态可视化:提供未开始、进行中、已完成、出错四种状态的视觉区分
- 表单集成:与步骤表单深度集成,支持步骤切换时的表单验证
- 动画效果:状态切换和布局转换时的平滑过渡动画
- 自定义配置:支持步骤标题、描述、图标等内容的自定义
- 响应式设计:在不同屏幕尺寸下自动调整布局,移动设备优先采用垂直布局
- 交互反馈:提供点击、拖拽等交互方式的视觉反馈
- 主题适配:支持浅色/深色主题,可自定义颜色和尺寸参数
技术实现
主进程(main.js)
主进程负责应用窗口管理和步骤数据的持久化存储,通过Electron的IPC机制提供步骤状态的保存与恢复功能,确保流程中断后可继续。
预加载脚本(preload.js)
使用contextBridge暴露步骤进度指示器的核心API,包括步骤状态管理、布局切换、进度保存等功能,确保渲染进程安全访问系统资源。
渲染进程(renderer.js)
实现组件的核心交互逻辑:
- 布局引擎:处理水平/垂直布局的切换与计算
- 状态管理器:维护步骤的状态变化与历史记录
- 表单集成器:处理步骤与表单的联动及验证逻辑
- 动画控制器:管理状态切换和布局转换的动画效果
- 响应式处理器:根据屏幕尺寸自动调整布局模式
样式实现(style.css)
通过CSS变量实现主题定制,使用Flexbox布局实现水平/垂直两种排列方式,为不同状态定义专属样式,通过CSS过渡实现平滑的状态切换效果。
代码结构
main.js- Electron主进程代码,管理窗口与数据持久化preload.js- 预加载脚本,安全暴露核心APIindex.html- 步骤指示器组件界面结构style.css- 样式定义,包含布局与状态样式renderer.js- 渲染进程逻辑,处理核心功能实现stepUtils.js- 工具类,提供步骤计算与状态转换方法stepConfig.js- 配置管理,处理布局与样式配置
核心代码示例
1. 布局切换实现
javascript
class StepIndicator {
constructor(container, options) {
this.container = container;
this.steps = options.steps || [];
this.currentStep = options.initialStep || 0;
this.layout = options.layout || 'horizontal'; // 默认为水平布局
// 初始化布局
this.initLayout();
// 响应窗口大小变化
window.addEventListener('resize', this.handleResize.bind(this));
}
// 初始化布局
initLayout() {
this.container.className = `step-indicator ${this.layout}`;
this.renderSteps();
}
// 切换布局
setLayout(layout) {
if (layout !== 'horizontal' && layout !== 'vertical') return;
this.layout = layout;
this.container.classList.remove('horizontal', 'vertical');
this.container.classList.add(layout);
this.renderSteps();
}
// 响应式布局处理
handleResize() {
if (window.innerWidth < 768 && this.layout === 'horizontal') {
this.setLayout('vertical'); // 小屏幕自动切换为垂直布局
} else if (window.innerWidth >= 768 && this.layout === 'vertical' &&
!this.userForcedLayout) {
this.setLayout('horizontal'); // 大屏幕自动切换为水平布局
}
}
// 渲染步骤
renderSteps() {
this.container.innerHTML = this.steps.map((step, index) => this.renderStep(step, index)).join('');
this.updateConnectors(); // 更新步骤间的连接线
}
}
2. 动态步骤状态管理
javascript
// 步骤状态定义:0-未开始,1-进行中,2-已完成,3-出错
const STEP_STATES = {
PENDING: 0,
ACTIVE: 1,
COMPLETED: 2,
ERROR: 3
};
// 更新步骤状态
updateStepState(index, state) {
if (index < 0 || index >= this.steps.length) return;
// 更新内部状态
this.steps[index].state = state;
// 更新UI
const stepElement = this.container.querySelector(`.step-item[data-index="${index}"]`);
if (!stepElement) return;
// 移除所有状态类
Object.values(STEP_STATES).forEach(s => {
stepElement.classList.remove(`state-${s}`);
});
// 添加当前状态类
stepElement.classList.add(`state-${state}`);
// 更新图标
const iconElement = stepElement.querySelector('.step-icon');
switch(state) {
case STEP_STATES.COMPLETED:
iconElement.innerHTML = '✓'; // 完成图标
break;
case STEP_STATES.ERROR:
iconElement.innerHTML = '!'; // 错误图标
break;
case STEP_STATES.ACTIVE:
iconElement.innerHTML = index + 1; // 当前步骤显示序号
break;
default:
iconElement.innerHTML = index + 1; // 未开始显示序号
}
// 触发状态变化事件
this.emit('stepStateChange', { index, state });
}
// 前进到下一步
nextStep() {
if (this.currentStep >= this.steps.length - 1) return;
// 标记当前步骤为已完成
this.updateStepState(this.currentStep, STEP_STATES.COMPLETED);
// 前进到下一步
this.currentStep++;
// 标记下一步为进行中
this.updateStepState(this.currentStep, STEP_STATES.ACTIVE);
this.emit('stepChange', { currentStep: this.currentStep });
}
// 返回到上一步
prevStep() {
if (this.currentStep <= 0) return;
// 标记当前步骤为未开始
this.updateStepState(this.currentStep, STEP_STATES.PENDING);
// 返回到上一步
this.currentStep--;
// 标记上一步为进行中
this.updateStepState(this.currentStep, STEP_STATES.ACTIVE);
this.emit('stepChange', { currentStep: this.currentStep });
}
3. 步骤表单集成
javascript
// 步骤表单集成器
class StepFormIntegrator {
constructor(stepIndicator, formContainer) {
this.stepIndicator = stepIndicator;
this.formContainer = formContainer;
this.forms = Array.from(formContainer.querySelectorAll('.step-form'));
// 初始化表单状态
this.initForms();
// 监听步骤变化
this.stepIndicator.on('stepChange', (e) => this.showStepForm(e.currentStep));
}
// 初始化表单
initForms() {
// 隐藏所有表单,只显示当前步骤表单
this.forms.forEach((form, index) => {
form.classList.toggle('active', index === this.stepIndicator.currentStep);
// 绑定表单提交事件
form.addEventListener('submit', (e) => {
e.preventDefault();
this.handleFormSubmit(index);
});
});
}
// 显示指定步骤的表单
showStepForm(stepIndex) {
this.forms.forEach((form, index) => {
form.classList.toggle('active', index === stepIndex);
});
}
// 处理表单提交
handleFormSubmit(stepIndex) {
const form = this.forms[stepIndex];
// 验证当前步骤表单
if (this.validateForm(form)) {
// 表单验证通过,保存表单数据
this.saveFormData(stepIndex, this.getFormData(form));
// 前进到下一步
this.stepIndicator.nextStep();
} else {
// 表单验证失败,标记步骤为错误状态
this.stepIndicator.updateStepState(stepIndex, STEP_STATES.ERROR);
// 显示错误提示
this.showFormErrors(form);
}
}
// 表单验证
validateForm(form) {
const inputs = form.querySelectorAll('[required]');
let isValid = true;
inputs.forEach(input => {
if (!input.checkValidity()) {
input.classList.add('invalid');
isValid = false;
} else {
input.classList.remove('invalid');
}
});
return isValid;
}
// 获取表单数据
getFormData(form) {
const formData = new FormData(form);
const data = {};
formData.forEach((value, key) => {
data[key] = value;
});
return data;
}
// 保存表单数据
saveFormData(stepIndex, data) {
// 通过IPC保存到主进程或本地存储
window.electron.saveStepData(stepIndex, data);
}
}
如何使用
基本使用
- 定义步骤配置和HTML结构
html
<div id="step-indicator" class="step-indicator"></div>
<div id="form-container">
<form class="step-form">
<!-- 第一步表单内容 -->
</form>
<form class="step-form">
<!-- 第二步表单内容 -->
</form>
<!-- 更多步骤表单 -->
</div>
- 初始化步骤指示器
javascript
// 步骤配置
const steps = [
{ title: '基本信息', description: '填写个人基本信息' },
{ title: '选择方案', description: '选择适合您的方案' },
{ title: '确认提交', description: '确认信息并提交' }
];
// 初始化步骤指示器
const stepIndicator = new StepIndicator('#step-indicator', {
steps: steps,
initialStep: 0,
layout: 'horizontal'
});
// 集成表单
const formIntegrator = new StepFormIntegrator(stepIndicator, '#form-container');
高级配置
- 自定义步骤样式 :通过
data属性设置
javascript
const steps = [
{
title: '上传文件',
description: '上传必要的证明文件',
icon: '📂', // 自定义图标
color: '#4285f4' // 自定义颜色
},
// 其他步骤...
];
- 布局切换与强制设置
javascript
// 切换为垂直布局
stepIndicator.setLayout('vertical');
// 强制设置布局,不受窗口大小影响
stepIndicator.setLayout('vertical', true);
- 手动控制步骤状态
javascript
// 标记第二步为出错状态
stepIndicator.updateStepState(1, STEP_STATES.ERROR);
// 跳转到指定步骤
stepIndicator.goToStep(2);
运行方法
- 安装依赖
bash
npm install
- 启动应用
bash
npm start
- 运行示例
bash
npm run demo
鸿蒙适配后结构(需整合到 Electron 鸿蒙项目模板中):
plaintext
ohos_hap/
├── electron/
│ ├── libs/
│ │ └── arm64-v8a/ # 鸿蒙核心库文件
│ │ ├── libelectron.so
│ │ ├── libadapter.so
│ │ ├── libffmpeg.so
│ │ └── libc++_shared.so
├── web_engine/
│ └── src/
│ └── main/
│ └── resources/
│ └── resfile/
│ └── resources/
│ └── app/ # 放置electron应用代码
│ ├── main.js
│ ├── package.json
│ └── src/
└── module.json5 # 鸿蒙应用配置文件
鸿蒙PC适配改造指南
1. 环境准备
-
系统要求:Windows 10/11、8GB RAM以上、20GB可用空间
-
工具安装 :
DevEco Studio 5.0+(安装鸿蒙SDK API 20+)
-
Node.js 18.x+
2. 获取Electron鸿蒙编译产物
-
下载Electron 34+版本的Release包(.zip格式)
-
解压到项目目录,确认
electron/libs/arm64-v8a/下包含核心.so库
3. 部署应用代码
将Electron应用代码按以下目录结构放置:

plaintext
web_engine/src/main/resources/resfile/resources/app/
├── main.js
├── package.json
└── src/
├── index.html
├── preload.js
├── renderer.js
└── style.css
4. 配置与运行
-
打开项目:在DevEco Studio中打开ohos_hap目录
-
配置签名 :
进入File → Project Structure → Signing Configs
-
自动生成调试签名或导入已有签名
-
连接设备 :
启用鸿蒙设备开发者模式和USB调试
-
通过USB Type-C连接电脑
-
编译运行:点击Run按钮或按Shift+F10
5. 验证检查项
-
✅ 应用窗口正常显示
-
✅ 窗口大小可调整,响应式布局生效
-
✅ 控制台无"SysCap不匹配"或"找不到.so文件"错误
-
✅ 动画效果正常播放
跨平台兼容性
| 平台 | 适配策略 | 特殊处理 |
|---|---|---|
| Windows | 标准Electron运行 | 无特殊配置 |
| macOS | 标准Electron运行 | 保留dock图标激活逻辑 |
| Linux | 标准Electron运行 | 确保系统依赖库完整 |
| 鸿蒙PC | 通过Electron鸿蒙适配层 | 禁用硬件加速,使用特定目录结构 |
鸿蒙开发调试技巧
1. 日志查看
在DevEco Studio的Log面板中过滤"Electron"关键词,查看应用运行日志和错误信息。
2. 常见问题解决
-
"SysCap不匹配"错误:检查module.json5中的reqSysCapabilities,只保留必要系统能力
-
"找不到.so文件"错误:确认arm64-v8a目录下四个核心库文件完整
-
窗口不显示:在main.js中添加app.disableHardwareAcceleration()
-
动画卡顿:简化CSS动画效果,减少重绘频率