HarmonyOS APP<玩转React>开源教程六:数据模型设计与实现

第6次:数据模型设计与实现

数据模型是应用的骨架,定义了数据的结构和类型。本次课程将深入设计 React 学习教程 App 的完整数据模型,为后续功能开发奠定基础。


学习目标

  • 理解数据模型设计原则
  • 掌握学习模块数据结构设计
  • 设计课程内容数据结构
  • 实现用户进度数据模型
  • 完成测验相关数据模型
  • 编写完整的 Models.ets 文件

效果

6.1 数据模型设计原则

设计原则

  1. 单一职责:每个接口只描述一种数据
  2. 类型安全:使用明确的类型,避免 any
  3. 可扩展性:预留扩展空间
  4. 一致性:命名和结构保持一致
  5. 文档化:添加清晰的注释

命名规范

typescript 复制代码
// 接口:名词,PascalCase
interface LearningModule { }
interface UserProgress { }

// 类型别名:描述性名称
type DifficultyType = 'beginner' | 'basic' | 'intermediate';
type CodeLanguage = 'javascript' | 'typescript';

// 常量:UPPER_SNAKE_CASE
const DEFAULT_USER_PROGRESS: UserProgress = { };

6.2 学习模块数据结构

模块层级关系

复制代码
App
 └── LearningModule (学习模块)
      └── Lesson (课程)
           └── LessonContent (课程内容)
                ├── ContentSection (内容段落)
                ├── CodeExample (代码示例)
                └── TOCItem (目录项)

LearningModule 接口

typescript 复制代码
/**
 * 学习模块
 * 代表一个完整的学习单元,如"React 简介"、"Hooks 基础"
 */
export interface LearningModule {
  /** 模块唯一标识 */
  id: string;

  /** 模块标题 */
  title: string;

  /** 模块描述 */
  description: string;

  /** 难度等级 */
  difficulty: DifficultyType;

  /** 图标(emoji 或图片路径) */
  icon: string;

  /** 主题色 */
  color: string;

  /** 课程数量 */
  lessonCount: number;

  /** 预计学习时间 */
  estimatedTime: string;

  /** 前置模块 ID 列表 */
  prerequisites: string[];

  /** 课程列表 */
  lessons: Lesson[];
}

Lesson 接口 课程接口

typescript 复制代码
/**
 * 课程
 * 模块下的具体课程单元
 */
export interface Lesson {
  /** 课程唯一标识 */
  id: string;

  /** 所属模块 ID */
  moduleId: string;

  /** 课程标题 */
  title: string;

  /** 课程描述 */
  description: string;

  /** 排序序号 */
  order: number;

  /** 课程内容 */
  content: LessonContent;

  /** 是否有代码练习 */
  hasPlayground: boolean;

  /** 是否有测验 */
  hasQuiz: boolean;
}

难度类型定义

typescript 复制代码
/**
 * 难度等级类型
 */
export type DifficultyType =
  | 'beginner'      // 入门
  | 'basic'         // 基础
  | 'intermediate'  // 进阶
  | 'advanced'      // 高级
  | 'ecosystem';    // 生态

6.3 课程内容数据结构

LessonContent 接口

typescript 复制代码
/**
 * 课程内容
 * 包含课程的所有内容元素
 */
export interface LessonContent {
  /** 内容段落列表 */
  sections: ContentSection[];

  /** 代码示例列表 */
  codeExamples: CodeExample[];

  /** 目录 */
  tableOfContents: TOCItem[];

  /** 关键要点 */
  keyTakeaways: string[];
}

ContentSection 接口

typescript 复制代码
/**
 * 内容段落类型
 */
export type SectionType =
  | 'text'     // 普通文本
  | 'code'     // 代码块
  | 'tip'      // 提示
  | 'warning'  // 警告
  | 'note';    // 注释

/**
 * 内容段落
 */
export interface ContentSection {
  /** 段落 ID */
  id: string;

  /** 段落标题 */
  title: string;

  /** 段落内容 */
  content: string;

  /** 段落类型 */
  type: SectionType;
}

CodeExample 接口

typescript 复制代码
/**
 * 代码语言类型
 */
export type CodeLanguage =
  | 'javascript'
  | 'typescript'
  | 'jsx'
  | 'tsx'
  | 'css'
  | 'json'
  | 'bash'
  | 'html'
  | 'text';

/**
 * 代码示例
 */
export interface CodeExample {
  /** 示例 ID */
  id: string;

  /** 示例标题 */
  title: string;

  /** 代码内容 */
  code: string;

  /** 代码语言 */
  language: CodeLanguage;

  /** 代码解释 */
  explanation: string;

  /** 是否可编辑(在调试器中) */
  isEditable: boolean;
}

TOCItem 接口

typescript 复制代码
/**
 * 目录项
 */
export interface TOCItem {
  /** 目录项 ID */
  id: string;

  /** 目录标题 */
  title: string;

  /** 层级(1-3) */
  level: number;
}

6.4 用户进度数据模型

UserProgress 接口

typescript 复制代码
/**
 * 用户进度
 * 记录用户的学习状态和成就
 */
export interface UserProgress {
  /** 已完成课程 ID 列表 */
  completedLessons: string[];

  /** 已完成模块 ID 列表 */
  completedModules: string[];

  /** 当前学习课程 ID */
  currentLesson: string | null;

  /** 连续学习天数 */
  learningStreak: number;

  /** 最后学习日期(YYYY-MM-DD) */
  lastStudyDate: string;

  /** 总学习时长(分钟) */
  totalStudyTime: number;

  /** 获得的徽章列表 */
  badges: Badge[];
}

/**
 * 默认用户进度
 */
export const DEFAULT_USER_PROGRESS: UserProgress = {
  completedLessons: [],
  completedModules: [],
  currentLesson: null,
  learningStreak: 0,
  lastStudyDate: '',
  totalStudyTime: 0,
  badges: []
};

Badge 接口

typescript 复制代码
/**
 * 徽章类别
 */
export type BadgeCategory =
  | 'progress'  // 进度类
  | 'streak'    // 连续学习类
  | 'quiz'      // 测验类
  | 'project';  // 项目类

/**
 * 成就徽章
 */
export interface Badge {
  /** 徽章 ID */
  id: string;

  /** 徽章名称 */
  name: string;

  /** 徽章描述 */
  description: string;

  /** 徽章图标 */
  icon: string;

  /** 获得日期 */
  earnedDate: string;

  /** 徽章类别 */
  category: BadgeCategory;
}

Bookmark 接口

typescript 复制代码
/**
 * 收藏
 */
export interface Bookmark {
  /** 课程 ID */
  lessonId: string;

  /** 模块 ID */
  moduleId: string;

  /** 添加时间 */
  addedAt: string;
}

6.5 测验相关数据模型

Quiz 接口

typescript 复制代码
/**
 * 测验
 */
export interface Quiz {
  /** 测验 ID */
  id: string;

  /** 所属模块 ID */
  moduleId: string;

  /** 所属课程 ID(可选) */
  lessonId?: string;

  /** 测验标题 */
  title: string;

  /** 题目列表 */
  questions: QuizItem[];

  /** 及格分数(百分制) */
  passingScore: number;

  /** 时间限制(秒,可选) */
  timeLimit?: number;
}

QuizItem 接口

typescript 复制代码
/**
 * 测验题目
 */
export interface QuizItem {
  /** 题目 ID */
  id: string;

  /** 题目内容 */
  question: string;

  /** 选项列表(通常 4 个) */
  options: string[];

  /** 正确答案索引(0-3) */
  correctAnswer: number;

  /** 答案解析 */
  explanation: string;

  /** 代码片段(可选) */
  codeSnippet?: string;
}

QuizResult 接口

typescript 复制代码
/**
 * 测验结果
 */
export interface QuizResult {
  /** 测验 ID */
  quizId: string;

  /** 得分(百分制) */
  score: number;

  /** 总题数 */
  totalQuestions: number;

  /** 是否通过 */
  passed: boolean;

  /** 用户答案列表 */
  answers: number[];

  /** 完成时间 */
  completedAt: string;

  /** 用时(秒) */
  timeSpent: number;
}

面试题相关模型

typescript 复制代码
/**
 * 面试题难度
 */
export type InterviewDifficulty = 'easy' | 'medium' | 'hard';

/**
 * 面试题目
 */
export interface InterviewQuestion {
  /** 题目 ID */
  id: string;

  /** 所属模块 ID */
  moduleId: string;

  /** 模块名称 */
  moduleName: string;

  /** 题目内容 */
  question: string;

  /** 选项列表 */
  options: string[];

  /** 正确答案索引 */
  correctAnswer: number;

  /** 答案解析 */
  explanation: string;

  /** 难度等级 */
  difficulty: InterviewDifficulty;

  /** 代码片段(可选) */
  codeSnippet?: string;
}

/**
 * 错题记录
 */
export interface WrongAnswerRecord {
  /** 题目 ID */
  questionId: string;

  /** 完整题目信息 */
  question: InterviewQuestion;

  /** 用户的错误答案 */
  userAnswer: number;

  /** 正确答案 */
  correctAnswer: number;

  /** 记录时间 */
  recordedAt: string;

  /** 尝试次数 */
  attemptCount: number;

  /** 是否已掌握 */
  isMastered: boolean;

  /** 最后尝试时间 */
  lastAttemptAt: string;
}

/**
 * 答题统计
 */
export interface QuizStatistics {
  /** 总答题数 */
  totalAnswered: number;

  /** 正确数 */
  correctCount: number;

  /** 错误数 */
  wrongCount: number;

  /** 正确率(0-100) */
  accuracyRate: number;

  /** 各模块统计 */
  moduleStats: Record<string, ModuleQuizStats>;

  /** 最后更新时间 */
  lastUpdated: string;
}

/**
 * 模块答题统计
 */
export interface ModuleQuizStats {
  moduleId: string;
  moduleName: string;
  totalQuestions: number;
  answeredCount: number;
  correctCount: number;
  accuracyRate: number;
}

/**
 * 默认答题统计
 */
export const DEFAULT_QUIZ_STATISTICS: QuizStatistics = {
  totalAnswered: 0,
  correctCount: 0,
  wrongCount: 0,
  accuracyRate: 0,
  moduleStats: {},
  lastUpdated: ''
};

6.6 其他辅助模型

SearchResult 接口

typescript 复制代码
/**
 * 搜索结果
 */
export interface SearchResult {
  /** 结果类型 */
  type: 'module' | 'lesson';

  /** ID */
  id: string;

  /** 标题 */
  title: string;

  /** 描述 */
  description: string;

  /** 匹配的文本 */
  matchedText: string;

  /** 模块 ID(课程结果时) */
  moduleId?: string;

  /** 模块标题 */
  moduleTitle?: string;

  /** 难度 */
  difficulty?: DifficultyType;
}

DailyQuestion 接口

typescript 复制代码
/**
 * 每日一题
 */
export interface DailyQuestion {
  /** 日期(YYYY-MM-DD) */
  date: string;

  /** 题目 */
  question: QuizItem;

  /** 来源模块 ID */
  moduleId: string;

  /** 来源课程 ID */
  lessonId: string;

  /** 是否已回答 */
  answered: boolean;

  /** 是否回答正确 */
  correct?: boolean;
}

6.7 实操:完成 Models.ets 文件

现在,让我们将所有数据模型整合到一个完整的文件中。

更新 entry/src/main/ets/models/Models.ets

typescript 复制代码
/**
 * 数据模型定义
 * React 教程应用的所有类型接口
 */

// ==================== 基础类型 ====================

export type DifficultyType = 'beginner' | 'basic' | 'intermediate' | 'advanced' | 'ecosystem';
export type CodeLanguage = 'javascript' | 'typescript' | 'jsx' | 'tsx' | 'css' | 'json' | 'bash' | 'html' | 'text';
export type SectionType = 'text' | 'code' | 'tip' | 'warning' | 'note';
export type BadgeCategory = 'progress' | 'streak' | 'quiz' | 'project';
export type InterviewDifficulty = 'easy' | 'medium' | 'hard';

// ==================== 学习模块 ====================

export interface LearningModule {
  id: string;
  title: string;
  description: string;
  difficulty: DifficultyType;
  icon: string;
  color: string;
  lessonCount: number;
  estimatedTime: string;
  prerequisites: string[];
  lessons: Lesson[];
}

export interface Lesson {
  id: string;
  moduleId: string;
  title: string;
  description: string;
  order: number;
  content: LessonContent;
  hasPlayground: boolean;
  hasQuiz: boolean;
}

export interface LessonContent {
  sections: ContentSection[];
  codeExamples: CodeExample[];
  tableOfContents: TOCItem[];
  keyTakeaways: string[];
}

export interface ContentSection {
  id: string;
  title: string;
  content: string;
  type: SectionType;
}

export interface CodeExample {
  id: string;
  title: string;
  code: string;
  language: CodeLanguage;
  explanation: string;
  isEditable: boolean;
}

export interface TOCItem {
  id: string;
  title: string;
  level: number;
}

// ==================== 用户进度 ====================

export interface UserProgress {
  completedLessons: string[];
  completedModules: string[];
  currentLesson: string | null;
  learningStreak: number;
  lastStudyDate: string;
  totalStudyTime: number;
  badges: Badge[];
}

export interface Badge {
  id: string;
  name: string;
  description: string;
  icon: string;
  earnedDate: string;
  category: BadgeCategory;
}

export interface Bookmark {
  lessonId: string;
  moduleId: string;
  addedAt: string;
}

export const DEFAULT_USER_PROGRESS: UserProgress = {
  completedLessons: [],
  completedModules: [],
  currentLesson: null,
  learningStreak: 0,
  lastStudyDate: '',
  totalStudyTime: 0,
  badges: []
};

// ==================== 测验相关 ====================

export interface Quiz {
  id: string;
  moduleId: string;
  lessonId?: string;
  title: string;
  questions: QuizItem[];
  passingScore: number;
  timeLimit?: number;
}

export interface QuizItem {
  id: string;
  question: string;
  options: string[];
  correctAnswer: number;
  explanation: string;
  codeSnippet?: string;
}

export interface QuizResult {
  quizId: string;
  score: number;
  totalQuestions: number;
  passed: boolean;
  answers: number[];
  completedAt: string;
  timeSpent: number;
}

export interface DailyQuestion {
  date: string;
  question: QuizItem;
  moduleId: string;
  lessonId: string;
  answered: boolean;
  correct?: boolean;
}

// ==================== 面试题库 ====================

export interface InterviewQuestion {
  id: string;
  moduleId: string;
  moduleName: string;
  question: string;
  options: string[];
  correctAnswer: number;
  explanation: string;
  difficulty: InterviewDifficulty;
  codeSnippet?: string;
}

export interface WrongAnswerRecord {
  questionId: string;
  question: InterviewQuestion;
  userAnswer: number;
  correctAnswer: number;
  recordedAt: string;
  attemptCount: number;
  isMastered: boolean;
  lastAttemptAt: string;
}

export interface QuizStatistics {
  totalAnswered: number;
  correctCount: number;
  wrongCount: number;
  accuracyRate: number;
  moduleStats: Record<string, ModuleQuizStats>;
  lastUpdated: string;
}

export interface ModuleQuizStats {
  moduleId: string;
  moduleName: string;
  totalQuestions: number;
  answeredCount: number;
  correctCount: number;
  accuracyRate: number;
}

export const DEFAULT_QUIZ_STATISTICS: QuizStatistics = {
  totalAnswered: 0,
  correctCount: 0,
  wrongCount: 0,
  accuracyRate: 0,
  moduleStats: {},
  lastUpdated: ''
};

// ==================== 搜索 ====================

export interface SearchResult {
  type: 'module' | 'lesson';
  id: string;
  title: string;
  description: string;
  matchedText: string;
  moduleId?: string;
  moduleTitle?: string;
  difficulty?: DifficultyType;
}

本次课程小结

通过本次课程,你已经:

✅ 理解了数据模型设计原则

✅ 设计了学习模块的完整数据结构

✅ 实现了课程内容的数据模型

✅ 完成了用户进度数据模型

✅ 设计了测验和面试题相关模型

✅ 编写了完整的 Models.ets 文件


课后练习

  1. 扩展模型:为 UserProgress 添加学习目标相关字段

  2. 添加验证:编写函数验证 LearningModule 数据的完整性

  3. 类型守卫:编写类型守卫函数判断对象是否为特定接口类型


下次预告

第7次:本地数据持久化

我们将深入学习数据持久化:

  • Preferences 存储详解
  • StorageUtil 工具类完善
  • 异步存储操作
  • 数据迁移与版本管理

让应用数据能够持久保存!

相关推荐
rmst2 小时前
列表的拖动排序动画原理
javascript·react.js·动效
myNameGL2 小时前
DevEco Studio链接虚拟机报错解决方法
harmonyos
nunumaymax2 小时前
【第二章-React面向组件编程(二】
react.js
大雷神3 小时前
HarmonyOS APP<玩转React>开源教程五:项目架构设计
harmonyos
Maimai108083 小时前
React Server Components 是什么?一文讲清 CSR、Server Components 与 Next.js 中的客户端/服务端组件
前端·javascript·css·react.js·前端框架·html·web3
深海呐13 小时前
鸿蒙 Video组件的基本使用(HarmonyOS-VideoView)
华为·harmonyos·harmonyos video·harmonyos 视频播放·harmonyos 播放器·harmonyos 播放视频
是稻香啊14 小时前
HarmonyOS6 ArkUI 无障碍悬停事件(onAccessibilityHover)全面解析与实战演示
华为·harmonyos·harmonyos6
前端不太难14 小时前
从小项目到大型鸿蒙 App 的架构变化
架构·状态模式·harmonyos
aqi0015 小时前
【送书活动】《鸿蒙HarmonyOS 6:应用开发从零基础到App上线》迎新送书啦
android·华为·harmonyos·鸿蒙