flutter架 构项目基础
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
# 【Demo】富文本渲染(RichTextContent:HTML → 题目/解析)
|
||||
|
||||
> 源文件:`lib/pages/demo/rich_text_demo.dart` | 分类:组件封装
|
||||
> 一句话:后端给的 HTML(题目/解析/听力材料)渲染成富文本 —— 还支持字号调节、深色模式、自定义样式。
|
||||
|
||||
---
|
||||
|
||||
## 一、这个 Demo 解决什么问题
|
||||
|
||||
教育 App 的题目/解析是**后端返回的 HTML 字符串**(`<h3>`、`<img>`、`<table>`、`<audio>`…),
|
||||
前端要把它渲染成漂亮的可交互富文本。本页演示 `RichTextContent`(`lib/core/components/rich_text_content.dart`):
|
||||
|
||||
- 完整渲染:标题、粗体、**上标下标**、`<ul>` 选项、`<table>` 表格;
|
||||
- `<audio>` 标签**自动替换成本项目的 AudioPlayerCard**;
|
||||
- 学生端能力:**字号 Aa± 实时调节、深色模式切换**(通过 `textStyle` 注入);
|
||||
- 自定义样式:`.answer` 类 → 红色加粗(`customStylesBuilder`)。
|
||||
|
||||
> 对照 Vue:相当于 `v-html` + 样式定制,但 Flutter 没有浏览器引擎,得用 flutter_html 这类包逐标签渲染。
|
||||
|
||||
---
|
||||
|
||||
## 二、怎么运行 / 演示内容
|
||||
|
||||
```dart
|
||||
runApp(const MaterialApp(home: RichTextDemoPage()));
|
||||
```
|
||||
|
||||
- 顶部控制栏:滑块拖字号(12~24)、切深色开关 → 正文实时变化;
|
||||
- 页面里:化学方程式上下标、本地图片(`asset://` 协议)、表格、听力音频、视频、红色加粗的答案 B。
|
||||
|
||||
---
|
||||
|
||||
## 三、核心知识点(新手向)
|
||||
|
||||
### 1. 一行渲染 HTML
|
||||
```dart
|
||||
RichTextContent(
|
||||
html: _html, // 后端返回的 HTML 字符串
|
||||
// 字号 + 深色模式都通过 textStyle 注入(学生端统一入口)
|
||||
textStyle: TextStyle(
|
||||
fontSize: _fontSize,
|
||||
height: 1.6,
|
||||
color: _dark ? Colors.white70 : const Color(0xFF333333),
|
||||
),
|
||||
)
|
||||
```
|
||||
**`textStyle` 注入是核心设计**:页面不重建 HTML、不改渲染器,只改一个 TextStyle 就全局换字号/颜色——学生端"无障碍调节"的标准做法。
|
||||
|
||||
### 2. 自定义样式:customStylesBuilder
|
||||
```dart
|
||||
customStylesBuilder: (element) {
|
||||
if (element.className.contains('answer')) {
|
||||
return const {'color': '#EF4444', 'font-weight': 'bold'};
|
||||
}
|
||||
return null; // 其他元素不特殊处理
|
||||
},
|
||||
```
|
||||
后端 HTML 里写 `<span class="answer">B</span>` → 渲染成红色加粗。**按 class 定制样式**,不用后端改结构。
|
||||
|
||||
### 3. 本地图片:asset:// 协议
|
||||
```html
|
||||
<img src="asset://assets/img/luola_logo.png" width="160" height="160"/>
|
||||
```
|
||||
`asset://` + 资源路径 = 加载本地资源图片(最稳,不受网络影响)。实际后端返回完整 URL 或相对路径(相对路径需业务层拼 baseUrl)。
|
||||
|
||||
### 4. audio 标签自动替换
|
||||
```html
|
||||
<audio src="asset://assets/audio/sample-30s.mp3" title="听力材料(30 秒)" controls></audio>
|
||||
```
|
||||
组件内部检测 `<audio>` → 替换成 `AudioPlayerCard`(见 [audio_player_demo.md](audio_player_demo.md))——听力题直接能播。
|
||||
|
||||
---
|
||||
|
||||
## 四、关键代码剖析
|
||||
|
||||
```dart
|
||||
static const String _html = '''
|
||||
<h3>第 1 题 · 阅读理解</h3>
|
||||
<p>光合作用是植物利用光能将<strong>二氧化碳</strong>和<strong>水</strong>合成有机物并释放氧气的过程。化学方程式:6CO<sub>2</sub> + 6H<sub>2</sub>O → C<sub>6</sub>H<sub>12</sub>O<sub>6</sub> + 6O<sub>2</sub>,面积用 x<sup>2</sup> 表示。</p>
|
||||
<img src="asset://assets/img/luola_logo.png" width="160" height="160"/>
|
||||
<ul>
|
||||
<li>A. 光合作用只发生在夜间</li>
|
||||
<li>B. 光合作用会释放氧气</li>
|
||||
</ul>
|
||||
<table border="1" cellpadding="6">
|
||||
<tr><th>条件</th><th>有光</th><th>黑暗</th></tr>
|
||||
<tr><td>释放 O₂</td><td>√</td><td>×</td></tr>
|
||||
</table>
|
||||
<audio src="asset://assets/audio/sample-30s.mp3" title="听力材料(30 秒)" controls></audio>
|
||||
<p><b>【解析】</b>正确答案:<span class="answer">B</span>。</p>
|
||||
''';
|
||||
```
|
||||
|
||||
字号控制条(12~24 共 12 档):
|
||||
```dart
|
||||
Slider(
|
||||
value: _fontSize,
|
||||
min: 12,
|
||||
max: 24,
|
||||
divisions: 12, // 档位数 → 滑块只能停在整数
|
||||
activeColor: const Color(0xFF3B82F6),
|
||||
onChanged: (v) => setState(() => _fontSize = v),
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、踩坑记录
|
||||
|
||||
1. **textStyle 只影响文本**:图片、表格、AudioPlayerCard 是各自样式——深色模式下卡片白底不随主题变(业务侧需按需适配);
|
||||
2. **内联 CSS 只支持常用属性**,复杂布局会降级(flutter_html 的边界,别拿它当浏览器);
|
||||
3. 公式(LaTeX)本 demo 未含:以后在 `RichTextContent` 的 `customWidgetBuilder` 里扩展(如 flutter_math_fork);
|
||||
4. 相对路径图片要业务层拼 baseUrl,别把裸相对路径直接塞进 html;
|
||||
5. 深色模式只是 `_dark` 布尔 + 换色,**页面底色/AppBar 也要跟着换**(本页手动处理了,主题化见 [theme_demo.md](theme_demo.md))。
|
||||
|
||||
---
|
||||
|
||||
## 六、扩展思考
|
||||
|
||||
- `<audio>` 替换成的播放器组件见 [audio_player_demo.md](audio_player_demo.md);
|
||||
- 富文本在真实考试页的运用见 [exam_demo.md](exam_demo.md)(题干 HTML 渲染);
|
||||
- 学生端"字号调节 + 深色模式"这类**偏好设置**,进阶做法是存进全局状态(Riverpod),见 [exam_architecture.md](../exam_architecture.md) 的 Riverpod 章节;
|
||||
- 真实项目:`_html` 换成接口返回的题目 HTML,`asset://` 换成 CDN 完整 URL 即可。
|
||||
Reference in New Issue
Block a user