consumer-app/pages/detail/richTextDetail.vue

240 lines
5.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="rich-text-detail-page">
<!-- 顶部导航栏 -->
<NavHeader :title="title || '详情'" />
<!-- 内容区域 -->
<scroll-view class="content-scroll" scroll-y="true">
<!-- 加载中 -->
<view class="loading-state" v-if="loading">
<text class="loading-text">加载中...</text>
</view>
<!-- 富文本内容 - 混合渲染 -->
<view class="content-wrapper" v-else-if="parsedContent && parsedContent.length > 0">
<block v-for="(item, index) in parsedContent" :key="index">
<!-- 使 image -->
<view v-if="item.type === 'image'" class="rich-text-image-wrapper">
<image
class="rich-text-image"
:src="item.src"
mode="widthFix"
:lazy-load="true"
></image>
</view>
<!-- 如果是文本内容,使用 rich-text -->
<rich-text v-else-if="item.type === 'text'" :nodes="item.html" class="rich-text-content"></rich-text>
</block>
</view>
<!-- 空数据提示 -->
<view class="empty-state" v-else>
<image
class="empty-icon"
src="/static/home/entry_icon.png"
mode="aspectFit"
></image>
<text class="empty-text"></text>
</view>
</scroll-view>
</view>
</template>
<script>
import NavHeader from "@/components/NavHeader/NavHeader.vue";
export default {
components: {
NavHeader
},
data() {
return {
title: '',
content: '',
parsedContent: [], // 解析后的内容数组
loading: false,
};
},
onLoad(options) {
// 从路由参数获取标题和内容
if (options.title) {
this.title = decodeURIComponent(options.title);
}
if (options.content) {
let content = decodeURIComponent(options.content);
// 解析 HTML分离图片和文本
this.parsedContent = this.parseHtmlContent(content);
} else {
uni.showToast({
title: "缺少内容",
icon: "none",
});
setTimeout(() => {
uni.navigateBack();
}, 1500);
}
},
methods: {
// 解析 HTML 内容,将图片和文本分离
parseHtmlContent(html) {
if (!html) return [];
const result = [];
let currentIndex = 0;
// 匹配所有 img 标签
const imgRegex = /<img([^>]*)>/gi;
let match;
let lastIndex = 0;
while ((match = imgRegex.exec(html)) !== null) {
// 添加图片之前的文本内容
if (match.index > lastIndex) {
const textContent = html.substring(lastIndex, match.index);
if (textContent.trim()) {
result.push({
type: 'text',
html: textContent
});
}
}
// 提取图片 src
const imgAttrs = match[1];
const srcMatch = imgAttrs.match(/src=["']([^"']+)["']/i);
if (srcMatch && srcMatch[1]) {
result.push({
type: 'image',
src: srcMatch[1]
});
}
lastIndex = match.index + match[0].length;
}
// 添加最后剩余的文本内容
if (lastIndex < html.length) {
const textContent = html.substring(lastIndex);
if (textContent.trim()) {
result.push({
type: 'text',
html: textContent
});
}
}
// 如果没有匹配到图片,直接返回整个内容作为文本
if (result.length === 0 && html.trim()) {
result.push({
type: 'text',
html: html
});
}
return result;
}
},
};
</script>
<style lang="scss" scoped>
.rich-text-detail-page {
height: 100vh;
background-color: #e2e8f1;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* 内容区域 */
.content-scroll {
flex: 1;
height: 0; // 配合 flex: 1 使用,让 scroll-view 可以滚动
}
.content-wrapper {
padding: 30rpx 20rpx;
background-color: #ffffff;
margin: 20rpx;
border-radius: 20rpx;
min-height: 200rpx;
box-sizing: border-box;
overflow-x: hidden;
overflow-y: visible;
word-wrap: break-word;
word-break: break-all;
// 图片容器样式
.rich-text-image-wrapper {
width: 100%;
margin: 20rpx 0;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
.rich-text-image {
width: 100%;
height: auto;
display: block;
max-width: 100%;
}
}
// 文本内容样式
.rich-text-content {
width: 100%;
display: block;
font-family: PingFang-SC, PingFang-SC;
font-size: 28rpx;
line-height: 1.8;
color: #333333;
word-wrap: break-word;
word-break: break-all;
box-sizing: border-box;
}
}
/* 加载状态 */
.loading-state {
display: flex;
justify-content: center;
align-items: center;
padding: 200rpx 0;
min-height: 500rpx;
.loading-text {
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 28rpx;
color: #999999;
}
}
/* 空数据提示 */
.empty-state {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 200rpx 0;
min-height: 500rpx;
.empty-icon {
width: 200rpx;
height: 200rpx;
margin-bottom: 40rpx;
opacity: 0.5;
}
.empty-text {
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 28rpx;
color: #999999;
}
}
</style>