feat(mini-program): 添加 Markdown 渲染组件支持回溯过去页面
- 创建 Markdown.vue 组件,解析并渲染 Markdown 格式内容 - 支持分割线 (---)、四级标题 (####)、列表项 (*-)、段落 - 更新 RecordView.vue 使用 Markdown 组件渲染事件内容和 AI 回复 - 样式采用紫色主题,与整体设计保持一致 解决 issues: 小程序回溯过去页面的 Markdown 内容以纯文本显示的问题
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<view class="markdown-container">
|
||||
<view v-for="(block, index) in parsedBlocks" :key="index" :class="block.type">
|
||||
<!-- 分割线 -->
|
||||
<view v-if="block.type === 'hr'" class="markdown-hr"></view>
|
||||
|
||||
<!-- 标题 -->
|
||||
<text v-else-if="block.type === 'h4'" class="markdown-h4">{{ block.content }}</text>
|
||||
|
||||
<!-- 列表项 -->
|
||||
<view v-else-if="block.type === 'li'" class="markdown-li">
|
||||
<text class="li-bullet">• </text>
|
||||
<text class="li-content">{{ block.content }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 普通段落 -->
|
||||
<text v-else class="markdown-p">{{ block.content }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
content: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
// 解析 Markdown 内容
|
||||
const parsedBlocks = computed(() => {
|
||||
if (!props.content) return []
|
||||
|
||||
const lines = props.content.split('\n')
|
||||
const blocks = []
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim()
|
||||
|
||||
// 跳过空行
|
||||
if (trimmed === '') continue
|
||||
|
||||
// 分割线
|
||||
if (trimmed === '---' || trimmed === '***' || trimmed === '___') {
|
||||
blocks.push({ type: 'hr', content: '' })
|
||||
continue
|
||||
}
|
||||
|
||||
// 四级标题 ####
|
||||
const h4Match = trimmed.match(/^####\s+(.+)/)
|
||||
if (h4Match) {
|
||||
blocks.push({ type: 'h4', content: h4Match[1] })
|
||||
continue
|
||||
}
|
||||
|
||||
// 列表项 * 或 -
|
||||
const liMatch = trimmed.match(/^[*\-]\s+(.+)/)
|
||||
if (liMatch) {
|
||||
blocks.push({ type: 'li', content: liMatch[1] })
|
||||
continue
|
||||
}
|
||||
|
||||
// 普通段落
|
||||
blocks.push({ type: 'p', content: trimmed })
|
||||
}
|
||||
|
||||
return blocks
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.markdown-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
/* 分割线 */
|
||||
.markdown-hr {
|
||||
height: 2rpx;
|
||||
background: linear-gradient(to right,
|
||||
rgba(168, 85, 247, 0.1) 0%,
|
||||
rgba(168, 85, 247, 0.4) 50%,
|
||||
rgba(168, 85, 247, 0.1) 100%
|
||||
);
|
||||
margin: 24rpx 0;
|
||||
border-radius: 2rpx;
|
||||
}
|
||||
|
||||
/* 标题 */
|
||||
.markdown-h4 {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: rgba(243, 232, 255, 0.95);
|
||||
margin: 16rpx 0 8rpx 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* 列表项 */
|
||||
.markdown-li {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
gap: 12rpx;
|
||||
padding: 8rpx 0;
|
||||
}
|
||||
|
||||
.li-bullet {
|
||||
color: #C084FC;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.5;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.li-content {
|
||||
flex: 1;
|
||||
color: rgba(243, 232, 255, 0.8);
|
||||
font-size: 24rpx;
|
||||
line-height: 1.6;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* 普通段落 */
|
||||
.markdown-p {
|
||||
display: block;
|
||||
color: rgba(243, 232, 255, 0.75);
|
||||
font-size: 24rpx;
|
||||
line-height: 1.6;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user