在这里插入图片描述

一、功能概述

本篇文章围绕“喝水记录应用”的首页仪表板页面展开,重点介绍如何在 Cordova Web 层OpenHarmony ArkTS 原生层 之间协同工作,实现本地 IndexedDB 数据统计、通过桥接接口把概要数据同步到原生侧,再由 ArkUI 组件以更流畅的方式承载和展示这些统计结果。全文采用 一小段代码 + 一小段文字说明 的交替方式,避免出现大片代码难以阅读的问题。

仪表板页面的核心目标是:在用户打开应用时,第一时间看到当天喝水进度、本周趋势以及常用快捷操作入口。Web 侧使用 HTML + CSS + JavaScript 渲染主界面和操作逻辑,原生侧用 ArkTS 编写一个简单的统计卡片组件,并通过 Cordova 插件拉取数据。下面从 Web 布局、数据统计、Cordova 桥接、ArkTS 组件实现四个方面逐步拆解。

二、Web 层仪表板布局

<div id="dashboard-page" class="page page-dashboard">
  <div class="dashboard-header">
    <h1>今日喝水概览</h1>
    <p id="dashboard-date"></p>
  </div>
  <div class="dashboard-cards">
    <div class="card" id="card-today-total">
      <div class="card-title">今日总饮水量</div>
      <div class="card-value" id="today-total-ml">0 ml</div>
    </div>
    <div class="card" id="card-today-progress">
      <div class="card-title">目标完成度</div>
      <div class="card-value" id="today-progress-percent">0%</div>
    </div>
  </div>
</div>

上面的 HTML 片段定义了仪表板页面的最基础结构,包括一个标题区域和两个统计卡片。dashboard-page 作为整页的容器,方便在单页应用中通过 display 或路由控制来切换显示;dashboard-header 展示页面标题和当前日期;dashboard-cards 内部放置两张简化的统计卡片,分别用于展示今日总饮水量和目标完成进度。通过为卡片的数值部分赋予独立 id(例如 today-total-mltoday-progress-percent),后续可以在 JavaScript 中直接更新它们的文本内容,实现数据驱动的视图刷新。

.page-dashboard {
  padding: 16px 24px;
}

.dashboard-header h1 {
  margin: 0;
  font-size: 20px;
}

.dashboard-cards {
  display: flex;
  gap: 12px;
  margin-top: 16px;
}

.dashboard-cards .card {
  flex: 1;
  padding: 16px;
  border-radius: 8px;
  background-color: #1f2933;
  color: #fff;
}

这段 CSS 为仪表板设置了基础的布局和样式。.page-dashboard 定义页面内边距,让内容不会紧贴窗口边缘;dashboard-cards 使用 flex 布局,将多张卡片横向排列并设置统一间距;.card 定义了卡片的背景色、圆角和内边距等视觉样式,以便在深色主题下保持良好对比度。通过把样式控制在一个较小的代码块中,可以在不依赖外部 UI 框架的情况下快速搭建可读性和可维护性都比较好的仪表板基础界面。

三、本地数据统计与页面初始化

async function loadDashboardData() {
  const today = new Date();
  const todayKey = today.toISOString().slice(0, 10);

  const totalMl = await db.getTodayTotalMl(todayKey);
  const goalMl = await db.getTodayGoalMl();

  const percent = goalMl > 0 ? Math.round((totalMl / goalMl) * 100) : 0;

  document.getElementById('today-total-ml').textContent = `${totalMl} ml`;
  document.getElementById('today-progress-percent').textContent = `${percent}%`;

  document.getElementById('dashboard-date').textContent = todayKey;
}

这段 JavaScript 函数 loadDashboardData 负责从本地数据库拉取当天的喝水统计数据并更新到仪表板的界面上。首先通过 toISOString().slice(0, 10) 得到形如 2025-12-11 的日期主键,用于在 IndexedDB 中进行查询;随后调用假定已经封装好的 db.getTodayTotalMldb.getTodayGoalMl,分别获取实际喝水总量和目标值。利用简单的数学计算得到当前完成度百分比,并通过 document.getElementById 获取对应的 DOM 元素,将最新数值写入其 textContent。最后同步更新顶部显示的日期字符串,使用户一眼就知道当前统计对应的是哪一天。

function initDashboardPage() {
  const page = document.getElementById('dashboard-page');
  if (!page) {
    return;
  }

  loadDashboardData().catch((err) => {
    console.error('[Dashboard] load data failed', err);
  });
}

initDashboardPage 是仪表板页面的统一入口初始化函数。在单页应用的路由系统中,当用户切换到仪表板页面时,只需要调用这个函数即可触发数据加载逻辑。函数首先检查页面容器是否存在,以避免在 DOM 尚未渲染完成时调用导致的空引用问题;随后调用 loadDashboardData,并在 catch 块中记录错误日志,方便排查数据库或渲染阶段出现的问题。通过把初始化逻辑封装在独立方法中,可以在原生层或其他页面中重复调用,保证代码结构清晰、职责单一。

四、Cordova 与 OpenHarmony 之间的数据桥接

function syncDashboardToNative() {
  const totalText = document.getElementById('today-total-ml')?.textContent || '0 ml';
  const percentText = document.getElementById('today-progress-percent')?.textContent || '0%';

  const payload = {
    totalMl: totalText,
    progress: percentText,
  };

  if (!window.cordova) {
    console.warn('[Dashboard] cordova not ready, skip native sync');
    return;
  }

  cordova.exec(
    () => {
      console.info('[Dashboard] sync to native success');
    },
    (err) => {
      console.error('[Dashboard] sync to native failed', err);
    },
    'WaterTrackerDashboard',
    'updateSummary',
    [payload]
  );
}

syncDashboardToNative 函数展示了如何在 Web 侧通过 Cordova 的 exec 接口把仪表板数据同步到 OpenHarmony ArkTS 插件中。首先从 DOM 中读取“今日总饮水量”和“目标完成度”的文本值,并组装成一个 payload 对象。随后检查 window.cordova 是否可用,如果 Cordova 尚未注入(例如页面刚初始化、deviceready 事件还未触发),则直接给出警告并终止同步,避免调用失败。真正的桥接调用中,使用 cordova.exec 指定插件名 WaterTrackerDashboard、动作名 updateSummary,并将 payload 放入参数数组。成功和失败回调中均打印日志,方便开发阶段观察 Web 与原生之间的通信是否正常。

document.addEventListener('deviceready', () => {
  initDashboardPage();
  syncDashboardToNative();
});

这段代码将仪表板初始化与数据同步挂载到 Cordova 提供的 deviceready 事件上。只有当 Cordova 完成初始化并且原生插件已经注册完毕后,deviceready 才会触发,因此在该事件回调中调用 initDashboardPagesyncDashboardToNative 可以大幅降低因时机不对而导致的通信错误。通过这种模式,Web 层只需关心“页面准备好”和“设备准备好”两个时点,就能完成从本地数据库统计到原生仪表板组件展示的一条完整链路。

五、OpenHarmony ArkTS 插件与 UI 组件实现

// entry/src/main/ets/plugins/WaterTrackerDashboardPlugin.ets
import common from '@ohos.app.ability.common';
import { DashboardStore } from '../store/DashboardStore';

export default class WaterTrackerDashboardPlugin {
  context: common.UIAbilityContext;

  constructor(ctx: common.UIAbilityContext) {
    this.context = ctx;
  }

  updateSummary(args: Array<Object>, callbackId: number) {
    const data = args[0] as { totalMl: string; progress: string };
    DashboardStore.updateSummary(data.totalMl, data.progress);
    // 这里可以通过 Cordova 框架回调给 JS 侧,表示调用完成
  }
}

上述 ArkTS 代码定义了一个极简的原生插件 WaterTrackerDashboardPlugin,用于接收来自 Web 层的仪表板概要数据。构造函数中保存了 UIAbilityContext 以便后续需要访问资源或启动页面时使用;updateSummary 方法则按照 Cordova 插件的惯例签名接收参数数组和回调编号。函数内部将 args[0] 解析为包含 totalMlprogress 字段的对象,然后调用一个简单的状态存储类 DashboardStore.updateSummary,以便在 ArkUI 界面中读取最新的数据并触发界面刷新。这里没有展示 Cordova 层对插件的注册细节,重点在于说明参数解析和状态更新的基本流程。

// entry/src/main/ets/store/DashboardStore.ets
export class DashboardStore {
  private static _totalMl: string = '0 ml';
  private static _progress: string = '0%';

  static updateSummary(totalMl: string, progress: string) {
    this._totalMl = totalMl;
    this._progress = progress;
  }

  static get totalMl() {
    return this._totalMl;
  }

  static get progress() {
    return this._progress;
  }
}

DashboardStore 是一个极简的全局状态存储类,用于在插件和 ArkUI 组件之间共享数据。通过两个私有静态字段 _totalMl_progress 保存当前仪表板概要信息,并通过 updateSummary 方法对其进行更新。ArkUI 界面在渲染时可以直接从 DashboardStore.totalMlDashboardStore.progress 中读取最新值,从而避免在界面层重复解析参数。虽然这种静态方式并不适合所有复杂场景,但对于简单的仪表板摘要展示来说,足够直观、易于理解,也方便在后续重构时替换为更完备的状态管理方案。

// entry/src/main/ets/pages/MainPage.ets
@Entry
@Component
struct MainPage {
  build() {
    Column() {
      Text(`今日总饮水量:${DashboardStore.totalMl}`)
        .fontSize(18)
        .margin({ top: 16 })

      Text(`目标完成度:${DashboardStore.progress}`)
        .fontSize(18)
        .margin({ top: 8 })
    }
    .padding(16)
  }
}

以上 ArkUI 组件 MainPage 展示了如何在鸿蒙原生界面中消费 DashboardStore 中的数据,实现一份简洁的原生仪表板摘要视图。@Entry@Component 装饰器表明这是一个入口组件,build 方法内部使用 Column 纵向布局容器,依次放置两行 Text 组件,分别显示“今日总饮水量”和“目标完成度”。通过字符串模板读取 DashboardStore.totalMlDashboardStore.progress,当插件更新状态后,ArkUI 的声明式 UI 机制会在下一次刷新时渲染出新的文本。虽然这里只是一个非常基础的文本展示示例,但在实际项目中可以很容易扩展为带图标、进度条甚至动画效果的复杂卡片组件。

六、小结

本篇文章以“喝水记录应用”的仪表板页面为例,展示了如何在 Cordova Web 层OpenHarmony ArkTS 原生层 之间协作:首先在 Web 端使用 HTML 和 CSS 构建基本的仪表板布局,通过 JavaScript 从 IndexedDB 读取当天的喝水总量和目标数据,并渲染到页面上;随后利用 Cordova 的 exec 接口,将概要数据打包为 JSON 对象发送给原生插件。在鸿蒙侧,使用 ArkTS 实现一个简单的插件类,负责解析参数并更新全局状态存储 DashboardStore,最后在 ArkUI 组件 MainPage 中消费这些状态,以声明式方式展示“今日总饮水量”和“目标完成度”这两个关键指标。

通过 一段代码一段文字 的形式,我们把整个链路拆解为若干容易理解的小步骤:页面布局、样式设置、数据统计、桥接调用、插件实现、状态管理以及 ArkUI 界面展示。这样的写法既避免了大片代码带来的阅读负担,又能清晰地体现 Cordova 和 OpenHarmony 在同一个饮水记录应用中各自承担的角色。后续在其他页面(例如记录列表、趋势分析、目标管理等)中,可以复用同样的桥接模式,将更多业务逻辑从 Web 层延伸到鸿蒙原生侧,从而在保持开发效率的同时,获得更好的性能和用户体验。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐