feat: 优化Markdown渲染器,修复粗体和列表项显示问题,确保内容正确换行

This commit is contained in:
yangzhe 2025-07-15 09:21:35 +08:00
parent d92c3cf73c
commit ef2e9c8d79
1 changed files with 481 additions and 18 deletions

View File

@ -9,9 +9,41 @@ import { marked } from 'marked';
import hljs from 'highlight.js';
import mpHtml from '@/node_modules/mp-html/dist/uni-app/components/mp-html/mp-html.vue';
//
const renderer = new marked.Renderer();
//
renderer.strong = function(text) {
//
const trimmedText = text.trim();
return `<strong class="custom-strong" style="font-weight:900 !important;display:inline !important;white-space:normal !important;word-break:normal !important;">${trimmedText}</strong>`;
};
// - 使
renderer.listitem = function(text) {
return `<li class="custom-list-item"><div class="list-item-wrapper" style="text-align:left !important;letter-spacing:normal !important;word-spacing:normal !important;text-justify:none !important;">${text}</div></li>`;
};
//
renderer.list = function(body, ordered) {
const type = ordered ? 'ol' : 'ul';
const className = ordered ? 'custom-ordered-list' : 'custom-unordered-list';
return `<${type} class="${className}">${body}</${type}>`;
};
//
renderer.paragraph = function(text) {
return `<p class="custom-paragraph">${text}</p>`;
};
//
renderer.link = function(href, title, text) {
return `<a href="${href}" title="${title || ''}" style="display:inline !important;white-space:normal !important;word-break:break-all !important;letter-spacing:normal !important;word-spacing:normal !important;text-align:left !important;">${text}</a>`;
};
// marked
marked.use({
renderer: new marked.Renderer(),
renderer: renderer,
highlight: function(code, lang) {
try {
return hljs.highlightAuto(code, [lang]).value;
@ -54,33 +86,294 @@ export default {
renderedContent() {
if (!this.content) return '';
try {
//
//
const styleTag = `<style>
* {
max-width: 100% !important;
word-break: normal !important; /* 改为normal避免中文被强制断行 */
word-wrap: break-word !important;
word-break: normal !important;
overflow-wrap: break-word !important;
box-sizing: border-box !important;
}
p {
display: inline-block !important; /* 使段落内联显示 */
/* 段落样式修复 */
.custom-paragraph, p {
display: block !important;
white-space: normal !important;
text-align: left !important;
margin: 10rpx 0 !important;
width: 100% !important;
line-height: 1.6 !important;
text-align: left !important; /* 改为左对齐,不要两端对齐 */
}
/* 解决粗体文本和普通文本换行问题 */
.custom-strong, strong, b {
display: inline !important;
font-weight: 900 !important;
white-space: normal !important;
word-break: normal !important;
overflow-wrap: break-word !important;
vertical-align: baseline !important;
position: static !important;
float: none !important;
margin: 0 !important;
padding: 0 !important;
}
/* 专门用于列表项内容包装的容器 */
.list-item-wrapper {
display: inline-block !important;
width: 100% !important;
white-space: normal !important;
/* 关键属性:防止内部元素分列 */
table-layout: fixed !important;
word-break: normal !important;
text-align: left !important;
text-justify: none !important;
letter-spacing: normal !important;
word-spacing: normal !important;
text-align-last: left !important;
}
/* 内联元素修复 */
span, a, em, strong, .custom-strong, b {
display: inline !important;
white-space: normal !important;
vertical-align: baseline !important;
float: none !important;
position: static !important;
width: auto !important;
height: auto !important;
/* 确保内部不会有奇怪的换行 */
word-break: keep-all !important;
}
/* 特别针对粗体文本 */
.custom-strong, strong, b {
font-weight: bold !important;
display: inline !important;
vertical-align: baseline !important;
position: static !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
float: none !important;
width: auto !important;
word-break: keep-all !important;
word-wrap: normal !important;
line-height: inherit !important;
color: inherit !important; /* 确保颜色正确继承 */
}
/* 有序列表样式 */
.custom-ordered-list, ol {
display: block !important;
counter-reset: item !important;
padding-left: 0 !important;
margin: 10rpx 0 !important;
width: 100% !important;
list-style-type: none !important;
}
/* 无序列表样式 */
.custom-unordered-list, ul {
display: block !important;
padding-left: 0 !important;
margin: 10rpx 0 !important;
width: 100% !important;
list-style-type: none !important;
}
/* 列表项共用样式 */
.custom-list-item, ol li, ul li {
display: flex !important;
padding-left: 0 !important;
margin-bottom: 8rpx !important;
width: 100% !important;
position: relative !important;
/* 确保内容在一行显示 */
flex-wrap: nowrap !important;
align-items: flex-start !important; /* 顶部对齐 */
}
/* 列表项内容样式 */
.custom-list-item > *:not(ol):not(ul),
ol li > *:not(ol):not(ul),
ul li > *:not(ol):not(ul) {
flex: 1 !important;
display: inline !important;
white-space: normal !important;
word-break: normal !important;
width: auto !important;
/* 确保文本不会被分列 */
column-count: 1 !important;
column-width: auto !important;
column-span: all !important;
text-align: left !important; /* 确保文本左对齐 */
justify-content: flex-start !important; /* 左对齐 */
text-justify: none !important; /* 禁用两端对齐 */
letter-spacing: normal !important; /* 正常字间距 */
word-spacing: normal !important; /* 正常词间距 */
}
/* 列表项内的p标签特殊处理 */
ol li p, ul li p, .custom-list-item p {
display: inline !important;
margin: 0 !important;
padding: 0 !important;
width: auto !important;
white-space: normal !important;
}
/* 有序列表项编号 */
.custom-ordered-list > .custom-list-item {
counter-increment: item !important;
}
.custom-ordered-list > .custom-list-item::before,
ol > li::before {
content: counter(item)"." !important;
min-width: 40rpx !important;
width: 40rpx !important;
font-weight: bold !important;
text-align: right !important;
margin-right: 8rpx !important;
padding-right: 0 !important;
flex-shrink: 0 !important;
align-self: flex-start !important; /* 顶部对齐 */
padding-top: 1rpx !important; /* 微调垂直位置 */
}
/* 无序列表项标记 */
.custom-unordered-list > .custom-list-item::before,
ul > li::before {
content: "-" !important;
min-width: 40rpx !important;
width: 40rpx !important;
font-weight: bold !important;
text-align: center !important;
margin-right: 8rpx !important;
padding-right: 0 !important;
flex-shrink: 0 !important;
align-self: flex-start !important; /* 顶部对齐 */
padding-top: 1rpx !important; /* 微调垂直位置 */
}
/* 代码块样式 */
pre, code {
white-space: pre-wrap !important;
word-wrap: break-word !important;
word-break: break-all !important;
overflow-wrap: break-word !important;
}
/* 禁用可能导致问题的CSS特性 */
* {
column-count: 1 !important;
column-gap: 0 !important;
column-rule: none !important;
column-span: all !important;
column-width: auto !important;
columns: auto !important;
}
${this.customStyle || ''}
</style>`;
// MarkdownHTML
const htmlContent = marked(this.content);
// Markdown
let processedContent = this.content;
// Markdown
const paragraphs = processedContent.split('\n\n');
const processedParagraphs = paragraphs.map(paragraph => {
//
return paragraph.replace(/\*\*([^*]+?)\*\*/g, (match, content) => {
// HTML
return `<strong style="font-weight:900 !important;display:inline !important;">${content}</strong>`;
});
});
//
processedContent = processedParagraphs.join('\n\n');
// 使markedMarkdown
let htmlContent = marked(processedContent);
// HTML
htmlContent = htmlContent
// **
.replace(/\*\*([^*]+?)\*\*/g, (match, content) => {
return `<strong style="font-weight:900 !important;display:inline !important;">${content}</strong>`;
});
// HTML
let processedHtml = htmlContent;
// div
processedHtml = processedHtml.replace(/<p([^>]*)>(.*?)<\/p>/gs, (match, attrs, content) => {
//
return `<p${attrs} style="white-space:normal !important;word-break:normal !important;overflow-wrap:break-word !important;">${content}</p>`;
});
// 使
processedHtml = processedHtml.replace(
/<strong/g,
'<strong style="font-weight:900 !important;display:inline !important;white-space:normal !important;word-break:normal !important;overflow-wrap:break-word !important;color:inherit !important;"'
);
// HTML
processedHtml = processedHtml
.replace(/&lt;strong/g, '<strong')
.replace(/&lt;\/strong&gt;/g, '</strong>');
//
processedHtml = `
<style>
strong, .custom-strong, b {
font-weight: 900 !important;
display: inline !important;
color: inherit !important;
white-space: normal !important;
word-break: normal !important;
overflow-wrap: break-word !important;
}
p, div, span {
white-space: normal !important;
word-break: normal !important;
overflow-wrap: break-word !important;
text-align: left !important; /* 左对齐 */
text-justify: none !important; /* 禁用两端对齐 */
}
/* 关键样式:确保文本流不被打断 */
p strong, p b, strong, b {
display: inline !important;
white-space: normal !important;
}
/* 针对段落内部元素的处理 */
p > * {
display: inline !important;
}
/* 链接样式 */
a {
display: inline !important;
white-space: normal !important;
word-break: break-all !important;
letter-spacing: normal !important; /* 正常字间距 */
word-spacing: normal !important; /* 正常词间距 */
text-align: left !important; /* 左对齐 */
}
/* 禁用所有可能导致文本被拉伸的样式 */
* {
text-align-last: left !important;
text-justify: none !important;
text-align: left !important;
letter-spacing: normal !important;
word-spacing: normal !important;
}
</style>
` + processedHtml;
// HTML
return styleTag + htmlContent;
return styleTag + processedHtml;
} catch (error) {
console.error('Markdown渲染错误:', error);
return `<p style="color: red;">Markdown渲染错误: ${error.message}</p>`;
@ -97,28 +390,198 @@ export default {
padding: 20rpx;
overflow-wrap: break-word;
word-wrap: break-word;
word-break: normal; /* 改为normal避免中文被强制断行 */
word-break: normal;
}
/* 全局样式,确保所有元素都能自动换行 */
/* 全局样式 */
.markdown-container >>> * {
max-width: 100% !important;
white-space: normal !important;
word-break: normal !important; /* 改为normal */
word-break: normal !important;
overflow-wrap: break-word !important;
box-sizing: border-box !important;
}
/* 特别处理文本段落,避免单字换行 */
/* 段落样式 */
.markdown-container >>> .custom-paragraph,
.markdown-container >>> p {
display: inline-block !important;
text-align: left !important;
display: block !important;
/* margin: 10rpx 0 !important; */
width: 100% !important;
line-height: 1.6 !important;
text-align: left !important; /* 改为左对齐,不要两端对齐 */
}
/* 特别处理代码块 */
/* 专门用于列表项内容包装的容器 */
.markdown-container >>> .list-item-wrapper {
display: inline-block !important;
width: 100% !important;
white-space: normal !important;
/* 关键属性:防止内部元素分列 */
table-layout: fixed !important;
word-break: normal !important;
text-align: left !important;
text-justify: none !important;
letter-spacing: normal !important;
word-spacing: normal !important;
text-align-last: left !important;
}
/* 内联元素修复 */
.markdown-container >>> span,
.markdown-container >>> a,
.markdown-container >>> em,
.markdown-container >>> strong,
.markdown-container >>> .custom-strong,
.markdown-container >>> b {
display: inline !important;
white-space: normal !important;
vertical-align: baseline !important;
float: none !important;
position: static !important;
width: auto !important;
height: auto !important;
/* 确保内部不会有奇怪的换行 */
word-break: keep-all !important;
line-height: inherit !important;
}
/* 特别针对粗体文本 */
.markdown-container >>> .custom-strong,
.markdown-container >>> strong,
.markdown-container >>> b {
font-weight: 900 !important;
display: inline !important;
vertical-align: baseline !important;
position: static !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
float: none !important;
width: auto !important;
white-space: normal !important;
word-break: normal !important;
overflow-wrap: break-word !important;
word-wrap: normal !important;
line-height: inherit !important;
color: inherit !important; /* 确保颜色正确继承 */
font-size: inherit !important; /* 确保字体大小正确继承 */
font-family: inherit !important; /* 确保字体系列正确继承 */
text-decoration: none !important;
}
/* 有序列表样式 */
.markdown-container >>> .custom-ordered-list,
.markdown-container >>> ol {
display: block !important;
counter-reset: item !important;
padding-left: 0 !important;
margin: 10rpx 0 !important;
width: 100% !important;
list-style-type: none !important;
}
/* 无序列表样式 */
.markdown-container >>> .custom-unordered-list,
.markdown-container >>> ul {
display: block !important;
padding-left: 0 !important;
margin: 10rpx 0 !important;
width: 100% !important;
list-style-type: none !important;
}
/* 列表项共用样式 */
.markdown-container >>> .custom-list-item,
.markdown-container >>> ol li,
.markdown-container >>> ul li {
display: flex !important;
padding-left: 0 !important;
margin-bottom: 8rpx !important;
width: 100% !important;
position: relative !important;
/* 确保内容在一行显示 */
flex-wrap: nowrap !important;
align-items: flex-start !important; /* 顶部对齐 */
}
/* 列表项内容样式 */
.markdown-container >>> .custom-list-item > *:not(ol):not(ul),
.markdown-container >>> ol li > *:not(ol):not(ul),
.markdown-container >>> ul li > *:not(ol):not(ul) {
flex: 1 !important;
display: inline !important;
white-space: normal !important;
word-break: normal !important;
width: auto !important;
/* 确保文本不会被分列 */
column-count: 1 !important;
column-width: auto !important;
column-span: all !important;
text-align: left !important; /* 确保文本左对齐 */
justify-content: flex-start !important; /* 左对齐 */
text-justify: none !important; /* 禁用两端对齐 */
letter-spacing: normal !important; /* 正常字间距 */
word-spacing: normal !important; /* 正常词间距 */
}
/* 列表项内的p标签特殊处理 */
.markdown-container >>> ol li p,
.markdown-container >>> ul li p,
.markdown-container >>> .custom-list-item p {
display: inline !important;
margin: 0 !important;
padding: 0 !important;
width: auto !important;
white-space: normal !important;
}
/* 有序列表项编号 */
.markdown-container >>> .custom-ordered-list > .custom-list-item::before,
.markdown-container >>> ol > li::before {
counter-increment: item !important;
content: counter(item)"." !important;
min-width: 40rpx !important;
width: 40rpx !important;
font-weight: bold !important;
text-align: right !important;
margin-right: 8rpx !important;
padding-right: 0 !important;
flex-shrink: 0 !important;
align-self: flex-start !important; /* 顶部对齐 */
/* padding-top: 1rpx !important; 微调垂直位置 */
}
/* 无序列表项标记 */
.markdown-container >>> .custom-unordered-list > .custom-list-item::before,
.markdown-container >>> ul > li::before {
content: "-" !important;
min-width: 40rpx !important;
width: 40rpx !important;
font-weight: bold !important;
text-align: center !important;
margin-right: 8rpx !important;
padding-right: 0 !important;
flex-shrink: 0 !important;
align-self: flex-start !important; /* 顶部对齐 */
/* padding-top: 1rpx !important; 微调垂直位置 */
}
/* 禁用可能导致问题的CSS特性 */
.markdown-container >>> * {
column-count: 1 !important;
column-gap: 0 !important;
column-rule: none !important;
column-span: all !important;
column-width: auto !important;
columns: auto !important;
}
/* 代码块样式 */
.markdown-container >>> pre,
.markdown-container >>> code {
white-space: pre-wrap !important;
word-break: break-all !important; /* 代码可以在任何字符间断行 */
word-break: break-all !important;
overflow-wrap: break-word !important;
max-width: 100% !important;
}