|
@@ -1,6 +1,7 @@
|
|
|
// pages/user/map/index.js
|
|
|
const { museumApi } = require('../../../utils/api.js');
|
|
|
const { processHtmlContent } = require('../../../utils/htmlProcessor.js');
|
|
|
+const WxParse = require('../../../utils/wxParse/wxParse.js');
|
|
|
|
|
|
Page({
|
|
|
/**
|
|
@@ -62,6 +63,7 @@ Page({
|
|
|
* 加载详情数据
|
|
|
*/
|
|
|
loadDetailData() {
|
|
|
+ let that = this;
|
|
|
this.setData({
|
|
|
loading: true
|
|
|
});
|
|
@@ -69,11 +71,13 @@ Page({
|
|
|
museumApi.getMuseumDetail(2)
|
|
|
.then(response => {
|
|
|
if (response) {
|
|
|
- const parsedContent = this.parseContent(response.content || response.context);
|
|
|
- console.log('解析后的内容:', parsedContent);
|
|
|
+ // const parsedContent = this.parseContent(response.content || response.context);
|
|
|
+ let article = response.context;
|
|
|
+ // console.log('解析后的内容:', parsedContent);
|
|
|
+ WxParse.wxParse('article', 'html', article, that, 5);
|
|
|
this.setData({
|
|
|
detailData: response,
|
|
|
- contentItems: parsedContent
|
|
|
+ // contentItems: parsedContent
|
|
|
});
|
|
|
}
|
|
|
})
|
|
@@ -95,6 +99,59 @@ Page({
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
+ * 处理HTML实体编码
|
|
|
+ */
|
|
|
+ processHtmlEntities(text) {
|
|
|
+ if (!text) return '';
|
|
|
+ return text
|
|
|
+ .replace(/ /g, ' ')
|
|
|
+ .replace(/ /g, ' ')
|
|
|
+ .replace(/ /g, ' ')
|
|
|
+ .replace(/ /g, ' ')
|
|
|
+ .replace(/ /g, ' ');
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析style属性
|
|
|
+ */
|
|
|
+ parseStyleAttribute(styleStr) {
|
|
|
+ const styles = {};
|
|
|
+ if (styleStr) {
|
|
|
+ styleStr.split(';').forEach(rule => {
|
|
|
+ const [property, value] = rule.split(':').map(s => s.trim());
|
|
|
+ if (property && value) {
|
|
|
+ styles[property] = value;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return styles;
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查是否有删除线样式
|
|
|
+ */
|
|
|
+ hasStrikethrough(attributes) {
|
|
|
+ // 检查style属性中的text-decoration
|
|
|
+ const styleMatch = attributes.match(/style="([^"]*)"/i);
|
|
|
+ if (styleMatch) {
|
|
|
+ const styles = this.parseStyleAttribute(styleMatch[1]);
|
|
|
+ return styles['text-decoration']?.includes('line-through') ||
|
|
|
+ styles['text-decoration-line']?.includes('line-through');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查class属性中是否包含删除线相关类名
|
|
|
+ const classMatch = attributes.match(/class="([^"]*)"/i);
|
|
|
+ if (classMatch) {
|
|
|
+ const classes = classMatch[1].toLowerCase();
|
|
|
+ return classes.includes('strikethrough') ||
|
|
|
+ classes.includes('line-through') ||
|
|
|
+ classes.includes('deleted');
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
* 解析HTML内容为不同类型的内容项
|
|
|
*/
|
|
|
parseContent(content) {
|
|
@@ -105,26 +162,67 @@ Page({
|
|
|
|
|
|
// 定义所有匹配规则
|
|
|
const patterns = [
|
|
|
+ { regex: /<h[1-6]([^>]*?)>(.*?)<\/h[1-6]>/gi, type: 'heading', handler: (match) => { let text = match[2].replace(/<[^>]*>/g, ''); let attributes = match[1]; let isCenter = /text-align\s*:\s*center/i.test(attributes) || /style="[^"]*text-align\s*:\s*center[^"]*"/i.test(attributes); return { type: 'heading', content: this.processHtmlEntities(text), center: isCenter }; } },
|
|
|
+ {
|
|
|
+ regex: /<span[^>]*>(.*?)<\/span>/gi,
|
|
|
+ type: 'span',
|
|
|
+ handler: (match) => {
|
|
|
+ let text = match[1].replace(/<[^>]*>/g, '');
|
|
|
+ return {
|
|
|
+ type: 'span',
|
|
|
+ content: this.processHtmlEntities(text)
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 检测删除线标签(del, s, strike)
|
|
|
+ {
|
|
|
+ regex: /<(del|s|strike)[^>]*>(.*?)<\/(del|s|strike)>/gi,
|
|
|
+ type: 'strikethrough',
|
|
|
+ handler: (match) => {
|
|
|
+ let text = match[2].replace(/<[^>]*>/g, '');
|
|
|
+ return {
|
|
|
+ type: 'strikethrough',
|
|
|
+ content: this.processHtmlEntities(text)
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 检测带有删除线样式的任意标签
|
|
|
+ {
|
|
|
+ regex: /<(\w+)([^>]*style="[^"]*text-decoration[^"]*line-through[^"]*"[^>]*)>(.*?)<\/\1>/gi,
|
|
|
+ type: 'strikethrough',
|
|
|
+ handler: (match) => {
|
|
|
+ let text = match[3].replace(/<[^>]*>/g, '');
|
|
|
+ return {
|
|
|
+ type: 'strikethrough',
|
|
|
+ content: this.processHtmlEntities(text)
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 检测带有删除线类名的任意标签
|
|
|
+ {
|
|
|
+ regex: /<(\w+)([^>]*class="[^"]*(?:strikethrough|line-through|deleted)[^"]*"[^>]*)>(.*?)<\/\1>/gi,
|
|
|
+ type: 'strikethrough',
|
|
|
+ handler: (match) => {
|
|
|
+ let text = match[3].replace(/<[^>]*>/g, '');
|
|
|
+ return {
|
|
|
+ type: 'strikethrough',
|
|
|
+ content: this.processHtmlEntities(text)
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
{
|
|
|
regex: /<p[^>]*>(.*?)<\/p>/gi,
|
|
|
type: 'text',
|
|
|
handler: (match) => {
|
|
|
let text = match[1].replace(/<[^>]*>/g, '');
|
|
|
- // 将HTML实体编码的空格转换为对应数量的
|
|
|
- text = text.replace(/ /g, ' ');
|
|
|
- text = text.replace(/ /g, ' ');
|
|
|
- text = text.replace(/ /g, ' ');
|
|
|
- text = text.replace(/ /g, ' ');
|
|
|
- // 将普通空格也转换为
|
|
|
- text = text.replace(/ /g, ' ');
|
|
|
return {
|
|
|
type: 'text',
|
|
|
- content: text
|
|
|
+ content: this.processHtmlEntities(text)
|
|
|
};
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
- regex: /<div[^>]*class="[^"]*media-wrap[^"]*image-wrap[^"]*"[^>]*>.*?<img[^>]*src="([^"]+)"[^>]*(?:alt="([^"]*)")?\/?>.*?<\/div>/gi,
|
|
|
+ regex: /<div[^>]*class="[^"]*media-wrap[^"]*image-wrap[^"]*"[^>]*>.*?<img[^>]*src="([^"]+)"[^>]*(?:alt="([^"]*)")?\/?>.* ?<\/div>/gi,
|
|
|
type: 'image',
|
|
|
handler: (match) => ({
|
|
|
type: 'image',
|
|
@@ -133,7 +231,7 @@ Page({
|
|
|
})
|
|
|
},
|
|
|
{
|
|
|
- regex: /<div[^>]*class="[^"]*media-wrap[^"]*video-wrap[^"]*"[^>]*>.*?<video[^>]*src="([^"]+)"[^>]*(?:poster="([^"]*)")?\/?>.*?<\/div>/gi,
|
|
|
+ regex: /<div[^>]*class="[^"]*media-wrap[^"]*video-wrap[^"]*"[^>]*>.*?<video[^>]*src="([^"]+)"[^>]*(?:poster="([^"]*)")?\/?>.* ?<\/div>/gi,
|
|
|
type: 'video',
|
|
|
handler: (match) => ({
|
|
|
type: 'video',
|
|
@@ -142,7 +240,7 @@ Page({
|
|
|
})
|
|
|
},
|
|
|
{
|
|
|
- regex: /<div[^>]*class="[^"]*media-wrap[^"]*audio-wrap[^"]*"[^>]*>.*?<audio[^>]*src="([^"]+)"[^>]*(?:title="([^"]*)")?\/?>.*?<\/div>/gi,
|
|
|
+ regex: /<div[^>]*class="[^"]*media-wrap[^"]*audio-wrap[^"]*"[^>]*>.*?<audio[^>]*src="([^"]+)"[^>]*(?:title="([^"]*)")?\/?>.* ?<\/div>/gi,
|
|
|
type: 'audio',
|
|
|
handler: (match) => ({
|
|
|
type: 'audio',
|
|
@@ -161,17 +259,49 @@ Page({
|
|
|
if ((item.type === 'text' && item.content.trim()) || item.type !== 'text') {
|
|
|
matches.push({
|
|
|
index: match.index,
|
|
|
+ length: match[0].length,
|
|
|
item: item
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
-
|
|
|
+
|
|
|
// 按照在原HTML中的位置排序
|
|
|
matches.sort((a, b) => a.index - b.index);
|
|
|
+
|
|
|
+ // 移除重叠的匹配项(保持原始顺序,只过滤真正重复的内容)
|
|
|
+ const filteredMatches = [];
|
|
|
+ const typesPriority = ['heading', 'strikethrough', 'span', 'text']; // 优先级从高到低
|
|
|
+
|
|
|
+ for (let i = 0; i < matches.length; i++) {
|
|
|
+ const current = matches[i];
|
|
|
+ let shouldSkip = false;
|
|
|
+
|
|
|
+ // 检查是否与已添加的项有重叠
|
|
|
+ for (let j = 0; j < filteredMatches.length; j++) {
|
|
|
+ const existing = filteredMatches[j];
|
|
|
+ // 检查是否有重叠
|
|
|
+ if (current.index < existing.index + existing.length &&
|
|
|
+ current.index + current.length > existing.index) {
|
|
|
+ // 如果有重叠,比较优先级
|
|
|
+ const currentPriority = typesPriority.indexOf(current.item.type);
|
|
|
+ const existingPriority = typesPriority.indexOf(existing.item.type);
|
|
|
+
|
|
|
+ // 只有当前项优先级明显低于已存在项时才跳过
|
|
|
+ if (currentPriority > existingPriority && existingPriority !== -1) {
|
|
|
+ shouldSkip = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!shouldSkip) {
|
|
|
+ filteredMatches.push(current);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
// 提取排序后的内容项
|
|
|
- return matches.map(match => match.item);
|
|
|
+ return filteredMatches.map(match => match.item);
|
|
|
},
|
|
|
|
|
|
/**
|