如何阻止Marked插件将所有内容都用p标签包裹起来

正在用marked+highlight.js写项目,以下是配置(Vue项目)

import marked from 'marked'
import hljs from 'highlight.js'
import 'highlight.js/styles/googlecode.css'
marked.setOptions({
  highlight: (code) => hljs.highlightAuto(code).value
})
Vue.directive('highlight', function(el, { value }) {
  console.log(marked(value))
  el.innerHTML = marked(value)
})

但是打印出来的marked(value)结果却是:

<p><h1 id="title">title</h1></p>
<p><h2 id="-">标题</h2></p>
<p><p>标题</p></p>
<p><h3 id="-">第二个标题</h3></p>
<p><p>第二段文档</p></p>
<pre><code class="lang-html">&lt;button&gt;&lt;/button&gt;
</code></pre>

所有的代码都被p标签包裹起来了。请问如何解决这个问题?

阅读 5.3k
2 个回答

首先,需要澄清以下概念。

  1. marked模块的作用是用来将markdown文档转为html文档

  2. highlight.js的作用是用来高亮html的代码部分

因此,

  1. 如果你的文档已经是html文档了,没有必要再使用marked

  2. 如果需要高亮代码,那么只需要高亮 pre code包裹的部分

来看下面的示例

const marked = require('marked')
const hljs = require('highlight.js')

marked.setOptions({
  highlight: (code) => hljs.highlightAuto(code).value
})
const html = `
<h1>Heading1</h1>
<h2>Heading2</h2>
<pre><code>var a = 10<code><pre>
`
console.log(marked(html))

最后打印的结果是

<p><h1>Heading1</h1></p>
<p><h2>Heading2</h2></p>
<p><pre><code>var a = 10<code><pre></p>

来看第二个示例

const marked = require('marked')
const hljs = require('highlight.js')

marked.setOptions({
  highlight: (code) => hljs.highlightAuto(code).value
})
const markdown = `
# Heading1
## Heading2
    var a = 10
`
console.log(marked(markdown))

打印的结果是

<h1 id="heading1">Heading1</h1>
<h2 id="heading2">Heading2</h2>
<pre><code><span class="hljs-selector-tag">var</span> <span class="hljs-selector-tag">a</span> = <span class="hljs-number">10</span>
</code></pre>

由此,可以判断你传入的value,其实已经是html文档了,不需要marked再转换一次,只需要使用highlight.js高亮代码块即可。

最后改为以下代码即可

import hljs from 'highlight.js'
import 'highlight.js/styles/googlecode.css'

Vue.directive('highlight',function (el) {
  let blocks = el.querySelectorAll('pre code');
  blocks.forEach((block)=>{
    hljs.highlightBlock(block)
  })
})

p标签这个在低版本是会存在,我是vue2的项目,用的v4版本的marked,最新的15用了es最新的语法,比方说at啥的,需要装插件。
下面贴一个html过滤p标签的代码,规则是如果p标签外面有标签,那么就去掉这个p标签,但保留内容。

// 最后统一处理 p 标签
const processHtml = (html) => {
  // 使用正则表达式匹配被其他标签包裹的p标签
  const wrappedPTagPattern = /<(\w+)[^>]*>(?:\s*)<p>([^<]*(?:<(?!\/p>)[^<]*)*)<\/p>(?:\s*)<\/\1>/g;

  // 先处理被包裹的p标签
  html = html.replace(wrappedPTagPattern, (match, outerTag, content) => {
    // 保留外层标签和内容,只移除p标签
    return `<${outerTag}>${content}</${outerTag}>`;
  });

  // 处理剩余的独立p标签
  html = html.replace(/<p>([^<]*(?:<(?!\/p>)[^<]*)*)<\/p>/g, "$1");

  return html;
};

// 统一处理所有内容的 p 标签
htmlContent = processHtml(htmlContent);
宣传栏