feat: 优化Markdown渲染器,修复粗体和列表项显示问题,确保内容正确换行
This commit is contained in:
parent
d92c3cf73c
commit
ef2e9c8d79
|
@ -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>`;
|
||||
|
||||
// 渲染Markdown为HTML
|
||||
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');
|
||||
|
||||
// 使用marked处理剩余的Markdown语法
|
||||
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(/<strong/g, '<strong')
|
||||
.replace(/<\/strong>/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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue