feat(mini-program): 剧本卡片支持 Markdown 渲染
实现内容:
- 扩展 Markdown 组件支持三级标题 (###) 和粗体 (**text**)
- ScriptView.vue 卡片摘要使用 Markdown 组件渲染
- 新增 ScriptDetailView.vue 剧本详情页,展示完整 Markdown 内容
- 点击卡片可跳转查看详情,"路径映射"按钮使用@click.stop 避免事件冒泡
修改文件:
- components/Markdown.vue: 添加 h3 标题、粗体解析和样式
- pages/main/ScriptView.vue: 导入 Markdown 组件,修改摘要渲染方式,添加跳转逻辑
- pages/main/ScriptDetailView.vue: 新建详情页,展示剧本完整内容
- pages.json: 注册 ScriptDetailView 页面
解决 issues: 小程序"创造未来"页面剧本内容以纯文本显示,
无法正确渲染 Markdown 格式(标题、列表、粗体等)
This commit is contained in:
@@ -4,7 +4,10 @@
|
||||
<!-- 分割线 -->
|
||||
<view v-if="block.type === 'hr'" class="markdown-hr"></view>
|
||||
|
||||
<!-- 标题 -->
|
||||
<!-- 三级标题 -->
|
||||
<text v-else-if="block.type === 'h3'" class="markdown-h3">{{ block.content }}</text>
|
||||
|
||||
<!-- 四级标题 -->
|
||||
<text v-else-if="block.type === 'h4'" class="markdown-h4">{{ block.content }}</text>
|
||||
|
||||
<!-- 列表项 -->
|
||||
@@ -13,8 +16,10 @@
|
||||
<text class="li-content">{{ block.content }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 普通段落 -->
|
||||
<text v-else class="markdown-p">{{ block.content }}</text>
|
||||
<!-- 普通段落(处理粗体) -->
|
||||
<text v-else class="markdown-p">
|
||||
<text v-for="(segment, segIndex) in block.segments" :key="segIndex" :class="segment.bold ? 'bold' : ''">{{ segment.text }}</text>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -48,6 +53,13 @@ const parsedBlocks = computed(() => {
|
||||
continue
|
||||
}
|
||||
|
||||
// 三级标题 ###
|
||||
const h3Match = trimmed.match(/^###\s+(.+)/)
|
||||
if (h3Match) {
|
||||
blocks.push({ type: 'h3', content: h3Match[1] })
|
||||
continue
|
||||
}
|
||||
|
||||
// 四级标题 ####
|
||||
const h4Match = trimmed.match(/^####\s+(.+)/)
|
||||
if (h4Match) {
|
||||
@@ -62,12 +74,43 @@ const parsedBlocks = computed(() => {
|
||||
continue
|
||||
}
|
||||
|
||||
// 普通段落
|
||||
blocks.push({ type: 'p', content: trimmed })
|
||||
// 普通段落(处理粗体 **text**)
|
||||
const segments = parseBoldText(trimmed)
|
||||
blocks.push({ type: 'p', content: trimmed, segments })
|
||||
}
|
||||
|
||||
return blocks
|
||||
})
|
||||
|
||||
// 解析粗体文本 **text**
|
||||
const parseBoldText = (text) => {
|
||||
const segments = []
|
||||
const boldRegex = /\*\*(.+?)\*\*/g
|
||||
let lastIndex = 0
|
||||
let match
|
||||
|
||||
while ((match = boldRegex.exec(text)) !== null) {
|
||||
// 添加粗体前的普通文本
|
||||
if (match.index > lastIndex) {
|
||||
segments.push({ text: text.slice(lastIndex, match.index), bold: false })
|
||||
}
|
||||
// 添加粗体文本(去掉 ** 标记)
|
||||
segments.push({ text: match[1], bold: true })
|
||||
lastIndex = match.index + match[0].length
|
||||
}
|
||||
|
||||
// 添加剩余的普通文本
|
||||
if (lastIndex < text.length) {
|
||||
segments.push({ text: text.slice(lastIndex), bold: false })
|
||||
}
|
||||
|
||||
// 如果没有粗体,返回单个段落
|
||||
if (segments.length === 0) {
|
||||
segments.push({ text, bold: false })
|
||||
}
|
||||
|
||||
return segments
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -90,6 +133,15 @@ const parsedBlocks = computed(() => {
|
||||
}
|
||||
|
||||
/* 标题 */
|
||||
.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;
|
||||
}
|
||||
|
||||
.markdown-h4 {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
@@ -131,4 +183,10 @@ const parsedBlocks = computed(() => {
|
||||
line-height: 1.6;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* 粗体文本 */
|
||||
.bold {
|
||||
font-weight: 600;
|
||||
color: rgba(243, 232, 255, 0.9);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user