Skip to content

更优雅的markdown自定义内容渲染 #1

@hi9527-x

Description

@hi9527-x

你们把相同的内容,使用markdown-it解析了2次,来做自定义渲染。感觉完全没有必要,如下解析一次到html即可完成,不用浪费再解析一次

const mdit = markdownit({
  breaks: true,
  html: true,
  linkify: true,
  typographer: true,
  highlight(str, lang, attrs) {
    return `<!----MDIT_XYZ_CODE_BLOCK_${str}---->`
  },
})
import type { SlotsType, VNode } from 'vue'
import { defineComponent, h } from 'vue'
// import type { Options as MditOptions } from "markdown-it";
import 'github-markdown-css'
import { markdown2Html, regex, getNonEmptySlots } from './common';
import CodeHljs from "./CodeHljs";

type Slots = {
  codeBlock?: (params: { language: string, code: string }) => VNode[]
}
type Emits = {}
type Props = {
  // 项目定制,全局实例一次,为性能,不传参重新实例
  // mditOptions?: MditOptions
  content?: string
}

const Markdown = defineComponent<Props, Emits, string, SlotsType<Slots>>((props, ctx) => {
  return () => {
    const vNode: VNode[] = []
    let lastIndex = 0
    const { html } = markdown2Html(props.content || '')
    console.log(html);
    
    const matches = html.matchAll(/<pre>\s*<code\s+([^>]*)>(\s*)<!----MDIT_XYZ_CODE_BLOCK_([\s\S]*?)---->(\s*)<\/code>\s*<\/pre>/g)
    for (const match of matches) {
      if (match.index > lastIndex) {
        vNode.push(h('div', { innerHTML: html.slice(lastIndex, match.index) }))
      }
      
      let language = ''
      if (match[1]) {
        const langClass = match[1]
          .match(/\bclass\s*=\s*["']([^"']*)["']/i)?.[1]
          ?.split(/\s+/)
          ?.filter(Boolean)
          ?.find((cls) => cls.startsWith('language-'))

          if (langClass) {
            language = langClass.replace('language-', '')
          }
      }
      const code = match[3].trim()

      const slotComponents = getNonEmptySlots(ctx.slots.codeBlock?.({ language, code }))
      if (slotComponents.length) {
        vNode.push(...slotComponents)
      } else {
        vNode.push(h(CodeHljs, { language, code }))
      }
      lastIndex = match.index + match[0].length;
    }

     if (lastIndex < html.length) {
      vNode.push(h('div', { innerHTML: html.slice(lastIndex) }))
    }
    
    
    return <div class="markdown-body">
      {h('div', vNode)}
    </div>
  }
}, {
  props: ['content']
})

export default Markdown

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions