docs: 添加小程序剧本卡片 Markdown 渲染设计文档
设计内容:
- 扩展 Markdown 组件支持三级标题和粗体
- ScriptView.vue 卡片摘要使用 Markdown 渲染
- 新增 ScriptDetailView.vue 剧本详情页
- 点击卡片跳转查看详情
解决 issues: 小程序"创造未来"页面剧本内容以纯文本显示,
无法正确渲染 Markdown 格式(标题、列表、粗体等)
This commit is contained in:
@@ -0,0 +1,289 @@
|
|||||||
|
---
|
||||||
|
author: Peanut
|
||||||
|
created_at: 2026-04-07
|
||||||
|
purpose: 定义小程序"创造未来"页面剧本卡片的 Markdown 渲染方案
|
||||||
|
---
|
||||||
|
|
||||||
|
# 小程序剧本卡片 Markdown 渲染设计
|
||||||
|
|
||||||
|
## 问题背景
|
||||||
|
|
||||||
|
小程序"创造未来"页面(ScriptView.vue)中,剧本卡片当前以纯文本形式显示内容:
|
||||||
|
- 摘要区域:`<text class="script-summary">{{ getScriptSummary(script) }}</text>`
|
||||||
|
- 完整内容:存储在 `script.plotJson.fullContent` 中
|
||||||
|
|
||||||
|
但后端返回的剧本数据是 **Markdown 格式**:
|
||||||
|
```markdown
|
||||||
|
### 人物小传
|
||||||
|
花生米曾有过光芒闪耀的"破土而出"时刻...
|
||||||
|
|
||||||
|
### 戏剧驱动力
|
||||||
|
- 主人公当下最想要的一件具体的东西是:成为武林高手。
|
||||||
|
- 为了得到它,他必须承受或放弃的是:原本正常的生活节奏...
|
||||||
|
|
||||||
|
#### 第一场:抉择
|
||||||
|
- **时间**:日
|
||||||
|
- **地点**:花生米家中
|
||||||
|
- **人物**:花生米
|
||||||
|
花生米(自言自语):"成为武林高手,这听起来多带劲啊..."
|
||||||
|
```
|
||||||
|
|
||||||
|
当前纯文本显示导致:
|
||||||
|
- 标题与普通文本无法区分
|
||||||
|
- 列表项没有项目符号
|
||||||
|
- 粗体等格式丢失
|
||||||
|
- 阅读体验差
|
||||||
|
|
||||||
|
## 设计方案
|
||||||
|
|
||||||
|
### 架构概述
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ ScriptView.vue │
|
||||||
|
│ ┌─────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 剧本卡片 (script-card) │ │
|
||||||
|
│ │ ┌─────────────────────────────────────────────┐ │ │
|
||||||
|
│ │ │ 标题 / persona │ │ │
|
||||||
|
│ │ ├─────────────────────────────────────────────┤ │ │
|
||||||
|
│ │ │ 摘要区域 (Markdown 渲染 - 前 200 字符) │ │ │
|
||||||
|
│ │ │ ### 人物小传 │ │ │
|
||||||
|
│ │ │ 花生米曾有过光芒闪耀的... │ │ │
|
||||||
|
│ │ └─────────────────────────────────────────────┘ │ │
|
||||||
|
│ │ [路径映射 →] (点击跳转详情页) │ │
|
||||||
|
│ └─────────────────────────────────────────────────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼ 点击卡片
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ ScriptDetailView.vue (新增) │
|
||||||
|
│ ┌─────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 返回 剧本标题 │ │
|
||||||
|
│ ├─────────────────────────────────────────────────────┤ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ 完整 Markdown 内容渲染 │ │
|
||||||
|
│ │ ### 人物小传 │ │
|
||||||
|
│ │ 花生米曾有过... │ │
|
||||||
|
│ │ ### 戏剧驱动力 │ │
|
||||||
|
│ │ - 主人公当下最想要... │ │
|
||||||
|
│ │ #### 第一场:抉择 │ │
|
||||||
|
│ │ - **时间**:日 │ │
|
||||||
|
│ │ ... │ │
|
||||||
|
│ └─────────────────────────────────────────────────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 组件复用
|
||||||
|
|
||||||
|
**已有组件**:[`mini-program/src/components/Markdown.vue`](mini-program/src/components/Markdown.vue)
|
||||||
|
|
||||||
|
当前支持的 Markdown 格式:
|
||||||
|
- ✅ 分割线 `---`
|
||||||
|
- ✅ 四级标题 `#### `
|
||||||
|
- ✅ 列表项 `* ` / `- `
|
||||||
|
- ✅ 普通段落
|
||||||
|
|
||||||
|
**需要扩展支持**:
|
||||||
|
- ❌ 三级标题 `### `
|
||||||
|
- ❌ 粗体 `**text**`
|
||||||
|
|
||||||
|
### 文件结构
|
||||||
|
|
||||||
|
```
|
||||||
|
mini-program/src/
|
||||||
|
├── components/
|
||||||
|
│ └── Markdown.vue # 扩展现有组件
|
||||||
|
├── pages/main/
|
||||||
|
│ ├── ScriptView.vue # 修改:卡片摘要使用 Markdown
|
||||||
|
│ └── ScriptDetailView.vue # 新增:剧本详情页
|
||||||
|
└── services/
|
||||||
|
└── epicScript.js # 现有服务,无需修改
|
||||||
|
```
|
||||||
|
|
||||||
|
## 实施细节
|
||||||
|
|
||||||
|
### 1. Markdown 组件扩展
|
||||||
|
|
||||||
|
**文件**:`mini-program/src/components/Markdown.vue`
|
||||||
|
|
||||||
|
**新增解析规则**:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 三级标题 ###
|
||||||
|
const h3Match = trimmed.match(/^###\s+(.+)/)
|
||||||
|
if (h3Match) {
|
||||||
|
blocks.push({ type: 'h3', content: h3Match[1] })
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 粗体 **text** (在段落内容中处理)
|
||||||
|
// 由于小程序不支持富文本内的 HTML,粗体需要特殊处理
|
||||||
|
// 方案:将包含粗体的段落拆分为多个文本段
|
||||||
|
```
|
||||||
|
|
||||||
|
**模板新增**:
|
||||||
|
```vue
|
||||||
|
<!-- 三级标题 -->
|
||||||
|
<text v-else-if="block.type === 'h3'" class="markdown-h3">{{ block.content }}</text>
|
||||||
|
```
|
||||||
|
|
||||||
|
**样式**:
|
||||||
|
```css
|
||||||
|
.markdown-h3 {
|
||||||
|
display: block;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgba(243, 232, 255, 0.95);
|
||||||
|
margin: 20rpx 0 12rpx 0;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. ScriptView.vue 修改
|
||||||
|
|
||||||
|
**修改点 1**:导入 Markdown 组件
|
||||||
|
```javascript
|
||||||
|
import Markdown from '../../components/Markdown.vue'
|
||||||
|
```
|
||||||
|
|
||||||
|
**修改点 2**:摘要区域使用 Markdown 渲染
|
||||||
|
```vue
|
||||||
|
<!-- 原代码 -->
|
||||||
|
<text class="script-summary" lines="3">{{ getScriptSummary(script) }}</text>
|
||||||
|
|
||||||
|
<!-- 修改后 -->
|
||||||
|
<view class="script-summary">
|
||||||
|
<Markdown :content="getScriptSummary(script)" />
|
||||||
|
</view>
|
||||||
|
```
|
||||||
|
|
||||||
|
**修改点 3**:添加点击跳转
|
||||||
|
```vue
|
||||||
|
<view class="script-card" @click="viewScriptDetail(script)">
|
||||||
|
<!-- 卡片内容 -->
|
||||||
|
</view>
|
||||||
|
```
|
||||||
|
|
||||||
|
**修改点 4**:跳转方法
|
||||||
|
```javascript
|
||||||
|
const viewScriptDetail = (script) => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/main/ScriptDetailView?id=${script.id}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. ScriptDetailView.vue 新建
|
||||||
|
|
||||||
|
**文件**:`mini-program/src/pages/main/ScriptDetailView.vue`
|
||||||
|
|
||||||
|
**核心结构**:
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<view class="detail-view">
|
||||||
|
<view class="detail-header">
|
||||||
|
<text class="detail-title">{{ script.title }}</text>
|
||||||
|
<text class="detail-theme">{{ script.theme }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view class="detail-content" scroll-y>
|
||||||
|
<Markdown :content="fullContent" />
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { useAppStore } from '../../stores/app.js'
|
||||||
|
import Markdown from '../../components/Markdown.vue'
|
||||||
|
|
||||||
|
const store = useAppStore()
|
||||||
|
const script = ref(null)
|
||||||
|
const fullContent = ref('')
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const pages = getCurrentPages()
|
||||||
|
const currentPage = pages[pages.length - 1]
|
||||||
|
const scriptId = currentPage.options.id
|
||||||
|
|
||||||
|
// 从 store 获取剧本详情
|
||||||
|
const targetScript = store.scripts.find(s => s.id === scriptId)
|
||||||
|
script.value = targetScript
|
||||||
|
|
||||||
|
// 获取完整内容
|
||||||
|
if (targetScript?.plotJson?.fullContent) {
|
||||||
|
fullContent.value = targetScript.plotJson.fullContent
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 摘要提取逻辑
|
||||||
|
|
||||||
|
**当前逻辑**:
|
||||||
|
```javascript
|
||||||
|
const getScriptSummary = (script) => {
|
||||||
|
const text = script.summary || script.content || ''
|
||||||
|
return text.replace(/\s+/g, ' ').trim()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**修改后**:
|
||||||
|
```javascript
|
||||||
|
const getScriptSummary = (script) => {
|
||||||
|
// 优先使用 summary 字段
|
||||||
|
if (script.summary) {
|
||||||
|
return script.summary
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从 fullContent 提取前 200 字符
|
||||||
|
const fullContent = script.plotJson?.fullContent || ''
|
||||||
|
if (fullContent) {
|
||||||
|
// 提取内容,去掉 Markdown 符号
|
||||||
|
return fullContent
|
||||||
|
.split('\n')
|
||||||
|
.filter(line => line.trim())
|
||||||
|
.slice(0, 5) // 取前 5 行
|
||||||
|
.join('\n')
|
||||||
|
.slice(0, 200) + '...'
|
||||||
|
}
|
||||||
|
|
||||||
|
return '暂无摘要'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 验收标准
|
||||||
|
|
||||||
|
- [x] Markdown 组件支持三级标题 `###`
|
||||||
|
- [x] Markdown 组件支持粗体 `**text**`(如无法完美支持,降级为普通文本)
|
||||||
|
- [x] ScriptView.vue 卡片摘要使用 Markdown 渲染
|
||||||
|
- [x] 点击卡片可跳转到详情页查看完整内容
|
||||||
|
- [x] 详情页正确渲染完整 Markdown 格式
|
||||||
|
- [x] 样式与现有设计保持一致
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
### 1. 粗体支持限制
|
||||||
|
|
||||||
|
微信小程序的 `<text>` 组件不支持富文本内的局部样式。
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
- 方案 A:使用正则将 `**text**` 拆分为多个 `<text>` 组件(复杂)
|
||||||
|
- 方案 B:降级处理,粗体标记移除但保留文字(简单)
|
||||||
|
|
||||||
|
**推荐**:先实现方案 B,如效果不佳再考虑方案 A。
|
||||||
|
|
||||||
|
### 2. 长内容加载
|
||||||
|
|
||||||
|
剧本完整内容可能较长(2000+ 字符),详情页使用 `<scroll-view>` 确保可滚动浏览。
|
||||||
|
|
||||||
|
### 3. 数据获取
|
||||||
|
|
||||||
|
- 剧本数据已通过 `store.fetchScripts()` 加载到 store
|
||||||
|
- 详情页从 store 根据 ID 获取,无需额外 API 调用
|
||||||
|
|
||||||
|
## 参考文档
|
||||||
|
|
||||||
|
- [uni-app 页面跳转](https://uniapp.dcloud.net.cn/api/router.html)
|
||||||
|
- [uni-app scroll-view](https://uniapp.dcloud.net.cn/component/scroll-view.html)
|
||||||
|
- 已有 Markdown 组件:`mini-program/src/components/Markdown.vue`
|
||||||
Reference in New Issue
Block a user