轻松记录您
灵感和创意

如何自己开发个Markdown编辑器(2)

重构预览我们为了避免受页面全局样式影响,是在iframe中做的预览,而且是直接把html字符串传给iframe的“srcdoc”来控制内容。如果想要给它添加样式,要么在iframe中引入样式文件,要么动态添加style标签。虽然这都可以通过拼接html字符串的方式来实现,但这样太难维护,而且不易扩展。所以我想把iframe中的内容做成一个独立的页面,页面向外暴露一些方法,用于更新页面内容与添加样式。

首先新建文件src/previewer/index.ts,作为预览页面的入口文件,先简单的写个console.log用于等下验证是否生效

console.log(‘这是预览器的内部页面’)

然后修改webpack.config.js,在entry中添加previewer,并在plugin中为其添加个html模板

// ...
entry: {
  app: ['./src/index.tsx'],
  // 预览器页面入口
  previewer: ['./src/previewer/index.ts'],
},
// ...
plugins: [
  // ...
  new HtmlWebPackPlugin({
    title: 'Markdown Previewer',
    chunks: ['previewer'],
    filename: 'previewer.html',
  }),
  // ...
],
// ...

然后修改预览组件src/components/previewer.tsx中iframe的src

return (
  <iframe
    title="previewer"
    src="previewer.html"
    className="w-full h-full"
  />
)

重启工程,在控制台看到了预览器内部页面的输出内容

说明入口正常,可以进一步做功能了。

先来实现更新内容,即要能够插入Markdown转换成的html内容。我们先在页面中插入一个div元素,用作整个文档的容器,修改src/previewer/index.ts

// 创建文档容器
const docWrapper = document.createElement('div')
docWrapper.setAttribute('id', 'doc-content')
// 将容器插入body
document.body.appendChild(docWrapper)

然后向外暴露一个更新内容的方法

// 避免ts检查错误
const wd = window as any
// 对外暴露更新
wd.updateDoc = (html: string) => {
  docWrapper.innerHTML = html
}

再次修改组件src/components/previewer.tsx,调用更新文档内容的方法

// ..
// iframe引用
const iframeRef = useRef<HTMLIFrameElement>(null)

// 文档内容变化时更新
useEffect(() => {
  if (iframeRef.current) {
    const wd = iframeRef.current.contentWindow as any
    if (wd && wd.updateDoc) {
      wd.updateDoc(marked(doc))
    }
  }
}, [doc])
// ...

功能正常,重构完成,下面来添加基础样式。

基础样式

我并不擅长文档排版,所以在github上找了个简单的Markdown样式,叫“Markdown-CSS”。我们先用它实现基本功能,不用考虑样式是否美观。从该项目的描述发现它并没有发布到npm,所以直接下载文件,将“Markdown.css”放到我们项目的src/previewer目录下。修改src/previewer/index.ts,引入Markdown.css

import './markdown.css'

效果

基础样式已经添加上了,但基础样式中的代码只是普通的文本,没有任何高亮。

代码高亮

marked不直接支持代码高亮,但提供了相关配置。我们使用highlight.js来格式化代码,先安装highlight.js

yarn add highlight.js

然后在组件previewer.tsx中配置marked

// ...
import hljs from 'highlight.js'
// ...

// 设置marked选项
marked.setOptions({
  langPrefix: 'hljs ',
  highlight: (code, lang) => {
    const hlCode = hljs.highlight(lang, code).value
    return hlCode
  },
})

然后在预览的页面中引入highlight.js所需的css

import 'highlight.js/styles/atom-one-dark.css'

highlight.js支持很多风格,我们先用atom-one-dark.css实现基本功能,后期改为通过设置动态加载。效果

今天时间有限,先做这些,下期再见

未经允许不得转载:坚果云Markdown » 如何自己开发个Markdown编辑器(2)
分享到: 更多 (0)

坚果云Markdown轻松记录您 灵感和创意

坚果云Markdown下载坚果云Markdown介绍