跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
TypeScript大前端

鸿蒙应用架构设计:基于 ArkTS 的声明式 UI 与响应式状态管理

综述由AI生成基于鸿蒙 ArkTS 的应用架构设计,涵盖声明式 UI 与响应式状态管理。内容包括开屏页倒计时跳转、学习模块打卡与目标统计、用户登录数据持久化、首页分类切换与搜索功能,以及多级分类筛选机制。通过组件化设计与状态驱动渲染,实现了前后端解耦与流畅交互,支持多端部署。

清酒独酌发布于 2026/3/30更新于 2026/5/2424 浏览
鸿蒙应用架构设计:基于 ArkTS 的声明式 UI 与响应式状态管理

项目概述

百得知识库页面展示

img

开屏页(Advertising):展示广告图片,包含倒计时功能,倒计时结束后自动跳转至主页面,提供用户短暂的品牌展示和加载时间

首页(Index.ets):应用主框架,实现底部 Tab 导航首页、学习、消息、我的,通过状态管理控制当前显示页面,并负责整体布局和背景设置

学习页(Learn):整合学习工具打卡、目标、学习平台和面试大全等模块入口,以卡片形式展示各类学习功能,提供清晰的学习路径导航

消息页(Message):展示消息统计总数量/未读数量,分类显示系统消息和通知公告,支持下拉刷新,点击可查看详情,提供未读消息计数提示

我的页(Mine):显示用户个人信息头像、昵称,提供编辑个人信息入口,整合功能列表反馈、设置等,处理登录/未登录状态的差异化展示和退出登录逻辑

登录页(LoginPage):实现用户身份认证,支持账号密码输入验证,含用户协议和隐私政策勾选及查看功能

开屏页:广告展示与倒计时跳转机制

img

倒计时控制机制通过状态变量 countDownSeconds(默认 3 秒)实现,每秒递减一次。

当倒计时结束时,系统会清除定时器以防内存泄漏,从 PreferencesUtil 恢复用户 token 和信息,并通过 router.replaceUrl 跳转到首页,同时在 onPageHide 中清理相关资源

// 展示开屏页面时间,单位秒
@State countDownSeconds: number = CommonConstant.ADVERTISING_TIME;
// 结束时间,单位秒
endTime: number = CommonConstant.ADVERTISING_END_TIME;

/**
 * 生命周期函数
 */
onPageShow() {
  this.endTime = setInterval(async () => {
    if (this.countDownSeconds === CommonConstant.ADVERTISING_END_TIME) {
      // 清除定时器
      clearInterval(this.endTime);
      // 获取对应的 token 等数据
      const token = PreferencesUtil.getData(CommonConstant.PREFERENCES_NAME, CommonConstant.TOKEN_NAME, '');
      const userInfo = PreferencesUtil.getData(CommonConstant.PREFERENCES_NAME, CommonConstant.USER_INFO, '');
      if (token && userInfo) {
        AppStorage.setOrCreate(CommonConstant.TOKEN_NAME, token);
        AppStorage.setOrCreate(CommonConstant.USER_INFO, JSON.parse(userInfo));
      }
      // 跳转到首页
      router.replaceUrl({ url: RouterConstant.PAGE_INDEX });
    } else {
      this.countDownSeconds--;
    }
  }, 1000);
}

/**
 * 生命周期函数:隐藏页面
 */
onPageHide() {
  // 清除定时任务
  clearInterval(this.endTime);
}
学习模块核心功能

img

打卡定位

img

判断当前位置是否存在且当天未打卡。如果未打卡,则调用 learnClockApi.learnClock 提交打卡信息。显示成功提示后跳转到学习工具页。若当天已打卡,则提示用户无需重复打卡。

// 核心打卡功能实现
async clock() {
  if (this.location !== '') {
    if (!this.isClock) {
      // 调用 API 进行打卡
      await learnClockApi.learnClock({ location: this.location, content: '学习打卡' });
      showToast('打卡成功,已连续打卡 200 天');
      router.replaceUrl({ url: RouterConstant.VIEWS_LEARN_TOOL });
    } else {
      showToast('今日已打过卡,不需要重复打卡');
    }
  }
}
目标进度统计与数据获取

img

通过 targetInfoApi 获取用户目标进度和分页数据。根据总数判断是否还有更多内容。若 isFlushed 为真,则刷新数据,否则追加记录更新页面显示状态并重置加载标识,防止重复操作。若 isUpdate 为真,则弹出已更新提示。

async getUserTargetData(isFlushed: boolean, isUpdate: boolean) {
  // 获取用户整体目标完成进度统计
  this.countData = await targetInfoApi.getTargetInfoCount();
  // 分页查询用户整体目标
  const pageResult = await targetInfoApi.pageListTargetInfo({ page: this.page, pageSize: this.pageSize });
  this.total = pageResult.total;
  // 判断总数据
  if (this.total > this.page * this.pageSize) {
    this.textShow = false;
  } else {
    this.textShow = true;
  }
  // 判断是否是刷新还是下拉
  isFlushed ? this.targetInfoVos = pageResult.records : this.targetInfoVos.push(...pageResult.records);
  // 展示页面数据
  this.isShow = true;
  // 节流,防止用户重复下拉
  this.isLoad = false;
  this.isRefreshing = false;
  // 是否刷新
  if (isUpdate) {
    showToast("已更新");
  }
}
目标添加滑动功能

img

通过 IBestDialog 弹出对话框添加新目标。验证输入后调用 targetInfoApi.addTargetInfo 保存并刷新列表。列表尾端每个目标提供'完成'和'删除'按钮。完成目标通过 targetInfoApi.completeTargetInfo 更新状态并提示。删除目标通过 IBestDialogUtil 弹出确认框后调用 targetInfoApi.deleteTargetInfo 删除。

// 添加目标对话框
IBestDialog({
  visible: $dialogVisible,
  title: "添加目标",
  showCancelButton: true,
  defaultBuilder: (): void => this.formInputContain(),
  beforeClose: async (action) => {
    if (action === 'cancel') { return true; }
    const value = this.inputTargetValue.trim();
    this.formInputError = !value;
    if (this.formInputError) {
      showToast('请输入目标内容');
      return false; // 阻止关闭
    }
    // 添加新目标
    await targetInfoApi.addTargetInfo({ content: value });
    showToast('添加目标成功');
    // 刷新列表
    this.page = 1;
    await this.aboutToAppear();
    return true; // 允许关闭对话框
  }
});

// 列表尾端操作
@Builder itemEnd(item: TargetInfoVo) {
  Row() {
    // 完成目标按钮
    Button({ type: ButtonType.Circle }) {
      Image($r('app.media.icon_finish'))
        .width(40)
        .aspectRatio(1);
    }
    .onClick(async () => {
      if (item.status === '1') {
        showToast('当前目标已完成,无需重复点击');
        return;
      }
      await targetInfoApi.completeTargetInfo({ id: item.id });
      showToast('目标已完成');
      router.replaceUrl({ url: RouterConstant.VIEWS_LEARN_TARGET });
    }).margin({ right: 10 });

    // 删除目标按钮
    Button({ type: ButtonType.Circle }) {
      Image($r('app.media.icon_delete'))
        .width(40)
        .aspectRatio(1);
    }
    .margin({ right: 10 })
    .onClick(async () => {
      IBestDialogUtil.open({
        title: "提示",
        message: "是否确认删除当前目标?",
        showCancelButton: true,
        onConfirm: async () => {
          await targetInfoApi.deleteTargetInfo({ id: item.id });
          showToast('删除目标成功');
          router.replaceUrl({ url: RouterConstant.VIEWS_LEARN_TARGET });
        }
      });
    });
  }.justifyContent(FlexAlign.SpaceBetween);
}
用户登录与隐私设置

img

img

用户登录成功后,将 token 和用户信息同时保存到内存和设备存储中,实现数据持久化。通过 AppStorage 存入内存,方便应用运行时快速访问。通过 PreferencesUtil 存入设备存储,保证应用重启后仍可读取。调用 userApi.getUserInfo 获取用户信息并同步保存。

// 登录成功后数据持久化存储
if (token) {
  // 内存存储
  AppStorage.setOrCreate(CommonConstant.TOKEN_NAME, token);
  // 设备存储
  PreferencesUtil.savaData(CommonConstant.PREFERENCES_NAME, CommonConstant.TOKEN_NAME, token);
  // 获取并存储用户信息
  const userInfo = await userApi.getUserInfo();
  AppStorage.setOrCreate(CommonConstant.USER_INFO, userInfo);
  PreferencesUtil.savaData(CommonConstant.PREFERENCES_NAME, CommonConstant.USER_INFO, JSON.stringify(userInfo));
}
首页内容展示系统
分类切换机制

img

通过两个 Column 分别显示'最新'和'最热门'标题。点击标题时切换下划线显示状态以标识选中项。重置分页并触发对应数据加载最新文章或热门文章。

Row({ space: 10 }) {
  Column() {
    Text($r('app.string.article_best_new'))
      .textStyles();
    // 选中标题会出现下划线
    if (this.newDividerShow) {
      Divider().dividerStyles();
    }
  }
  .onClick(() => {
    // 展示下划线
    this.hotDividerShow = false;
    this.newDividerShow = true;
    // 查询最新文章数据
    this.isShow = false;
    this.page = 1;
    this.getArticleNewDataList(true, true);
  });

  Column() {
    Text($r('app.string.article_best_hot'))
      .textStyles();
    // 选中标题会出现下划线
    if (this.hotDividerShow) {
      Divider().dividerStyles();
    }
  }
  .onClick(() => {
    this.newDividerShow = false;
    this.hotDividerShow = true;
    // 查询最热门文章数据
    this.isShow = false;
    this.page = 1;
  });
}
搜索功能实现

img

通过 Search 组件输入关键字。设置占位符和字体样式。用户提交时将关键字编码后赋值给标题。重置分页并调用 getArticleDataList 查询匹配的文章列表。保证搜索结果与界面展示同步更新。

// 搜索
Search({ placeholder: '请输入关键字', value: $$this.keyword })
  .placeholderFont({ size: 14 })
  .textFont({ size: 14 })
  .onSubmit(() => {
    // 处理标题
    this.title = encodeURIComponent(this.keyword);
    // 分页查询文章内容
    this.isShow = false;
    this.page = 1;
    this.getArticleDataList(true);
  })
  .width(CommonConstant.WIDTH_FULL)
  .height(30);
下拉刷新与上拉加载

img

通过 Refresh 包裹 List 渲染文章内容。每个列表项可点击跳转到文章详情页。滚动到底部时判断是否有更多数据,若有则分页加载最新或最热门文章。更新加载状态,防止重复请求。下拉刷新时重置分页和加载状态重新获取对应分类的文章数据,保证列表展示与数据同步更新。

Refresh({ refreshing: $$this.isRefreshing }) {
  // 内容组件
  List() {
    ForEach(this.articleContentList, (item: ArticleContentData) => {
      ListItem() {
        ArticleComponent({ articleContentData: item })
          .onClick(() => {
            // 路由到内容详情页
            router.pushUrl({ url: RouterConstant.VIEWS_HOME_ARTICLE_INFO, params: { "articleId": item.id } });
          });
      }
    });
  }
  .onReachEnd(() => {
    if (!this.isLoad) {
      if (this.total > this.page * this.pageSize) {
        this.isLoad = true;
        this.page++;
        if (this.newDividerShow) {
          // 分页查询最新文章数据
          this.getArticleNewDataList(false, false);
        }
        if (this.hotDividerShow) {
          // 分页查询最热门文章数据
          this.getArticleHotDataList(false, false);
        }
      } else {
        this.textShow = true;
      }
    }
  })
  .onRefreshing(() => {
    if (!this.isLoad) {
      this.isLoad = true;
      this.textShow = false;
      // 页面恢复到 1
      this.page = 1;
      if (this.newDividerShow) {
        // 分页查询最新文章数据
        this.getArticleNewDataList(true, true);
      }
      if (this.hotDividerShow) {
        // 分页查询最热门文章数据
        this.getArticleHotDataList(true, true);
      }
    }
  });
多级分类与筛选机制
状态设计与管理分类 UI 交互设计

img

通过状态变量记录当前选中分类(全部、基础、进阶、高级)。点击不同分类时切换下划线显示状态。重置分页。将选中的难度赋值给 difficultyCategory。调用 getArticleList 重新加载对应分类的文章列表。实现界面与数据同步更新的条件筛选效果。

// 文章难度分类相关状态
@State allDividerShow: boolean = true;
@State basicDividerShow: boolean = false;
@State advancedDividerShow: boolean = false;
@State seniorDividerShow: boolean = false;
// 当前难度分类值
@State difficultyCategory: string = '';
// 当前内容分类(从路由参数获取)
@State contentCategory: string = '';

// 条件筛选标题栏
Row({ space: 10 }) {
  Column() {
    Text($r('app.string.all_condition'))
      .textStyles();
    // 选中标题会出现下划线
    if (this.allDividerShow) {
      Divider().dividerStyles();
    }
  }
  .onClick(() => {
    // 更新选中状态
    this.allDividerShow = true;
    this.basicDividerShow = false;
    this.advancedDividerShow = false;
    this.seniorDividerShow = false;
    // 重置分页并重新加载数据
    this.isShow = false;
    this.page = 1;
    this.getArticleList(true, true);
  });

  Column() {
    Text($r('app.string.basic_condition'))
      .textStyles();
    if (this.basicDividerShow) {
      Divider().dividerStyles();
    }
  }
  .onClick(() => {
    this.allDividerShow = false;
    this.basicDividerShow = true;
    this.advancedDividerShow = false;
    this.seniorDividerShow = false;
    this.isShow = false;
    this.page = 1;
    this.difficultyCategory = 'basic';
    this.getArticleList(true, true);
  });

  Column() {
    Text($r('app.string.advanced_condition'))
      .textStyles();
    if (this.advancedDividerShow) {
      Divider().dividerStyles();
    }
  }
  .onClick(() => {
    this.allDividerShow = false;
    this.basicDividerShow = false;
    this.advancedDividerShow = true;
    this.seniorDividerShow = false;
    this.isShow = false;
    this.page = 1;
    this.difficultyCategory = 'advanced';
    this.getArticleList(true, true);
  });

  Column() {
    Text($r('app.string.senior_condition'))
      .textStyles();
    if (this.seniorDividerShow) {
      Divider().dividerStyles();
    }
  }
  .onClick(() => {
    this.allDividerShow = false;
    this.basicDividerShow = false;
    this.advancedDividerShow = false;
    this.seniorDividerShow = true;
    this.isShow = false;
    this.page = 1;
    this.difficultyCategory = 'senior';
    this.getArticleList(true, true);
  });
}
总结

通过 '百得知识库' 项目充分体现鸿蒙应用在组件化设计、状态驱动渲染与分布式数据管理上的优势,借助 ArkTS 与方舟框架的声明式编程模型,结合 @State、AppStorage、Router 等特性,实现前后端解耦与流畅交互,依托分布式架构与组件复用能力,开发者可以在统一代码体系下快速构建多端协同场景,实现 '一次开发,多端部署'。

目录

  1. 项目概述
  2. 百得知识库页面展示
  3. 开屏页:广告展示与倒计时跳转机制
  4. 学习模块核心功能
  5. 打卡定位
  6. 目标进度统计与数据获取
  7. 目标添加滑动功能
  8. 用户登录与隐私设置
  9. 首页内容展示系统
  10. 分类切换机制
  11. 搜索功能实现
  12. 下拉刷新与上拉加载
  13. 多级分类与筛选机制
  14. 状态设计与管理分类 UI 交互设计
  15. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • AI 赋能 Python:基于 LLM + Pandas 的自动化数据清洗实操
  • ADI SHARC C/C++ 编译器指令优化
  • OpenClaw 实战指南:从零部署与核心原理解析
  • 网络安全工程师职业定义、核心技能与主流认证指南
  • 掌握 C++ 模板与内存管理,消除代码冗余与内存泄漏
  • Ollama 本地部署教程:Windows/Linux/Mac 安装与使用指南
  • Web 安全实战:PHP Assert 绕过与文件读取
  • 网络安全核心基础知识详解
  • GLM-Image WebUI 高级功能解析:种子复现、负向提示词与批量生成
  • 普通产品经理转型 AI 产品经理的准备指南
  • 从零开始实现 LLaMa3 模型:核心架构与代码解析
  • Spring Boot 集成 Doris Stream Load 实现百万级数据实时同步
  • Windows 10/11 部署 OpenClaw 指南:环境搭建与机器人互联
  • 若依框架从 Spring Boot 2 升级到 Spring Boot 3 实战
  • Python 爬虫实战:抓取微信公众号文章内容
  • Windows 环境下 llama.cpp 编译与 Qwen 模型本地部署指南
  • CycleGAN 详解与实现:图像风格转换技术
  • GitHub Copilot 配置实战:避开常见陷阱与最佳实践
  • 自适应图像变焦与边界框变换用于无人机目标检测
  • Pencil.dev:AI 驱动设计工具安装与实战教程

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online