摘要:想用熟悉的HTML+CSS+JS开发鸿蒙应用吗?虽然鸿蒙没有官方Electron,但其强大的Web组件ArkTS结合,能实现媲美Electron的混合开发。本文带你深入原理,并通过一个完整的振动器控制应用,掌握鸿蒙版“Electron”开发精髓。


一、 什么是Electron?鸿蒙如何实现类似能力?

Electron 的成功在于它让Web技术突破了浏览器沙箱,能够直接调用系统API。其核心是:

  • Chromium:渲染UI

  • Node.js:提供系统能力

  • IPC通信:连接UI与系统

鸿蒙的解决方案

  • Web组件:替代Chromium,渲染Web页面

  • ArkTS:替代Node.js,提供原生能力

  • JavaScript Bridge:替代IPC,实现双向通信

架构对比图

text

Electron架构:
┌─────────────────┐    IPC     ┌─────────────────┐
│   HTML+CSS+JS   │ ◄─────────► │   Node.js API   │
│  (渲染进程)      │            │   (主进程)       │
└─────────────────┘            └─────────────────┘

鸿蒙混合架构:
┌─────────────────┐  JS Bridge  ┌─────────────────┐
│   HTML+CSS+JS   │ ◄─────────► │   ArkTS API     │
│  (Web组件)       │            │   (原生Ability)  │
└─────────────────┘            └─────────────────┘

二、 环境准备与项目结构

开发环境

  • DevEco Studio 4.0+

  • HarmonyOS SDK API 9+

项目结构

text

HarmonyWebDemo/
├── entry/src/main/ets/
│   ├── entryability/
│   └── pages/
│       └── Index.ets              # 主页面,承载Web组件
├── entry/src/main/resources/
│   └── rawfile/
│       ├── index.html            # Web页面
│       └── css/
│           └── style.css         # 样式文件
└── ...

三、 核心代码实现
1. 原生层:ArkTS能力提供者 (Index.ets)

typescript

import webview from '@ohos.web.webview';
import vibrator from '@ohos.vibrator';
import promptAction from '@ohos.promptAction';

@Entry
@Component
struct WebContainer {
  // 核心:Web组件控制器
  private webController: webview.WebviewController = new webview.WebviewController();
  
  build() {
    Column() {
      // 原生顶部标题栏
      Text('鸿蒙振动器控制')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 10 })
      
      // Web组件 - 承载Web内容
      Web({
        src: $rawfile('index.html'),
        controller: this.webController
      })
        .width('100%')
        .height('100%')
        .onControllerAttached(() => {
          // 关键:注册JS桥接
          this.setupJavaScriptBridge();
        })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#f0f0f0')
  }

  // 建立JS与原生通信桥梁
  private setupJavaScriptBridge() {
    // 注册原生方法供JS调用
    this.webController.registerJavaScriptProxy({
      // 振动控制方法
      startVibration: (pattern: number[]) => {
        try {
          vibrator.startVibration({
            type: 'time',
            duration: pattern[0]  // 振动时长
          }, (error) => {
            if (error) {
              console.error('振动失败:', error);
              promptAction.showToast({ message: '振动失败!' });
            }
          });
          return JSON.stringify({ success: true });
        } catch (error) {
          return JSON.stringify({ success: false, error: error.message });
        }
      },
      
      // 停止振动
      stopVibration: () => {
        vibrator.stopVibration('time');
        return JSON.stringify({ success: true });
      },
      
      // 显示原生Toast
      showNativeToast: (message: string) => {
        promptAction.showToast({
          message: `来自Web: ${message}`,
          duration: 2000
        });
      }
    }, 'harmonyBridge', ['startVibration', 'stopVibration', 'showNativeToast']); 
    
    // 必须刷新才能生效
    this.webController.refresh();
  }
}
2. Web层:现代化UI界面 (index.html + CSS + JS)

HTML结构

html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>振动器控制面板</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <div class="container">
        <h1>🎛️ 振动控制面板</h1>
        <p class="desc">基于鸿蒙Web组件 + ArkTS混合开发</p>
        
        <div class="control-group">
            <div class="vibration-item" οnclick="startVibration(1000)">
                <div class="icon">📳</div>
                <div class="info">
                    <div class="title">短振动 (1秒)</div>
                    <div class="subtitle">轻微提醒</div>
                </div>
            </div>
            
            <div class="vibration-item" οnclick="startVibration(2000)">
                <div class="icon">🔔</div>
                <div class="info">
                    <div class="title">长振动 (2秒)</div>
                    <div class="subtitle">重要通知</div>
                </div>
            </div>
            
            <div class="vibration-item warning" οnclick="startCustomVibration()">
                <div class="icon">⚠️</div>
                <div class="info">
                    <div class="title">紧急振动</div>
                    <div class="subtitle">连续振动</div>
                </div>
            </div>
        </div>
        
        <button class="stop-btn" οnclick="stopVibration()">🛑 停止振动</button>
        
        <div class="status" id="status">就绪</div>
    </div>

    <script src="js/app.js"></script>
</body>
</html>

CSS样式 (style.css)

css

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    min-height: 100vh;
    padding: 20px;
}

.container {
    max-width: 400px;
    margin: 0 auto;
}

h1 {
    color: white;
    text-align: center;
    margin-bottom: 8px;
    font-size: 24px;
}

.desc {
    color: rgba(255, 255, 255, 0.8);
    text-align: center;
    margin-bottom: 30px;
    font-size: 14px;
}

.control-group {
    background: white;
    border-radius: 16px;
    padding: 20px;
    margin-bottom: 20px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}

.vibration-item {
    display: flex;
    align-items: center;
    padding: 16px;
    border-radius: 12px;
    margin-bottom: 12px;
    cursor: pointer;
    transition: all 0.3s ease;
    border: 2px solid transparent;
}

.vibration-item:hover {
    background: #f8f9fa;
    transform: translateY(-2px);
}

.vibration-item.warning {
    background: #fff3cd;
    border-color: #ffc107;
}

.icon {
    font-size: 24px;
    margin-right: 16px;
}

.info {
    flex: 1;
}

.title {
    font-weight: 600;
    color: #333;
    margin-bottom: 4px;
}

.subtitle {
    font-size: 12px;
    color: #666;
}

.stop-btn {
    width: 100%;
    padding: 16px;
    background: #dc3545;
    color: white;
    border: none;
    border-radius: 12px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.3s ease;
}

.stop-btn:hover {
    background: #c82333;
}

.status {
    text-align: center;
    color: white;
    margin-top: 20px;
    padding: 12px;
    background: rgba(255, 255, 255, 0.2);
    border-radius: 8px;
    font-size: 14px;
}

JavaScript逻辑 (app.js)

javascript

// 更新状态显示
function updateStatus(message, isError = false) {
    const statusEl = document.getElementById('status');
    statusEl.textContent = message;
    statusEl.style.color = isError ? '#ff6b6b' : 'white';
}

// 开始振动
async function startVibration(duration) {
    try {
        updateStatus('振动中...');
        
        // 关键:调用原生振动能力
        const result = await window.harmonyBridge.startVibration([duration]);
        const data = JSON.parse(result);
        
        if (data.success) {
            updateStatus(`振动成功: ${duration}ms`);
            // 调用原生Toast
            window.harmonyBridge.showNativeToast(`振动${duration}ms`);
        } else {
            throw new Error(data.error);
        }
    } catch (error) {
        console.error('振动失败:', error);
        updateStatus('振动失败!', true);
    }
}

// 自定义振动模式
function startCustomVibration() {
    // 模拟复杂振动模式
    startVibration(500);
    setTimeout(() => startVibration(300), 600);
    setTimeout(() => startVibration(700), 1000);
}

// 停止振动
async function stopVibration() {
    try {
        const result = await window.harmonyBridge.stopVibration();
        const data = JSON.parse(result);
        
        if (data.success) {
            updateStatus('振动已停止');
            window.harmonyBridge.showNativeToast('振动停止');
        }
    } catch (error) {
        updateStatus('停止失败!', true);
    }
}

// 页面加载完成
document.addEventListener('DOMContentLoaded', function() {
    updateStatus('点击上方项目开始振动');
});

四、 运行效果与核心机制

运行效果图

https://img-blog.csdnimg.cn/direct/abc123def456.png
(示意图:显示一个渐变紫色背景的应用,包含三个振动控制卡片和一个停止按钮)

核心机制详解

  1. 通信流程

    • Web点击事件 → 调用 window.harmonyBridge.startVibration()
      → ArkTS接收并执行振动 → 返回结果给Web

  2. 关键技术点

    • registerJavaScriptProxy:将ArkTS方法注入到Web的window对象

    • 异步通信:所有原生调用都是异步的,需要处理回调

    • 错误处理:完善的错误处理机制保证稳定性

  3. 安全考虑

    • Web只能调用预先注册的方法

    • 所有参数都需要验证和过滤

    • 敏感操作需要用户授权


五、 优势与局限

优势

  • ✅ 开发效率:UI开发速度提升3-5倍

  • ✅ 技术复用:现有Web团队快速转型

  • ✅ 生态丰富:可使用整个npm生态系统

  • ✅ 动态更新:Web资源可热更新

局限

  • ⚠️ 性能损耗:复杂动画性能不如原生

  • ⚠️ 能力限制:部分系统API无法暴露给Web

  • ⚠️ 包体积:Web核心会增加应用体积


六、 总结

通过鸿蒙的Web组件 + ArkTS桥接技术,我们成功实现了类似Electron的混合开发模式。这种方案特别适合:

  • 内容型应用:新闻、电商、社交媒体

  • 管理后台:设置、数据报表、监控面板

  • 快速原型:产品验证和概念演示

未来展望:随着鸿蒙生态的完善,我们可以期待更高效的通信机制、更丰富的能力映射,甚至出现第三方框架进一步简化开发流程。

Logo

赋能鸿蒙PC开发者,共建全场景原生生态,共享一次开发多端部署创新价值。

更多推荐