Vue2 中使用vue-markdown实现编辑器

摘要

本文将带你全面掌握如何在 Vue2 项目中使用 vue-markdown 组件,实现 Markdown 文本的解析与渲染。涵盖:

  • vue-markdown 简介与安装
  • ✅ 基础用法与核心属性
  • ✅ 高级功能(自定义样式、扩展语法)
  • ✅ 安全性处理(XSS 防护)
  • ✅ 实战案例:构建一个 Markdown 编辑预览器
  • ✅ 替代方案与未来展望

一、什么是 vue-markdown

vue-markdown 是一个基于 marked.js 的 Vue 组件,用于在 Vue 应用中轻松渲染 Markdown 格式的文本。

核心特点

  • 简单易用 :通过 <vue-markdown> 标签即可渲染 Markdown。
  • 轻量级 :依赖 marked,体积小,性能好。
  • 可定制:支持自定义标签、样式、扩展语法等。
  • Vue 友好:作为 Vue 组件集成,与 Vue 生态无缝衔接。

⚠️ 注意vue-markdown 项目在 GitHub 上已不再积极维护。但对于 Vue2 项目,它仍然是一个稳定、可靠的选择。对于新项目,建议考虑 ## Md-editor-v3 或其他现代方案。


二、环境准备与安装

2.1 前提条件

  • 已安装 Node.js 和 npm/yarn
  • 已创建 Vue2 项目(可通过 Vue CLI 创建)
bash 复制代码
vue create vue-markdown-demo
# 选择 Vue 2 preset
cd vue-markdown-demo

2.2 安装 vue-markdown

bash 复制代码
npm install vue-markdown --save
# 或
yarn add vue-markdown

依赖说明vue-markdown 依赖 marked,安装时会自动安装。


三、基础用法

3.1 全局注册组件

main.js 中全局注册 vue-markdown

javascript 复制代码
import Vue from 'vue'
import App from './App.vue'
import VueMarkdown from 'vue-markdown'

// 全局注册组件
Vue.component('vue-markdown', VueMarkdown)

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')

3.2 在组件中使用

创建 MarkdownDemo.vue

vue 复制代码
<template>
  <div class="markdown-demo">
    <h2>Markdown 基础示例</h2>
    
    <!-- 直接传入 Markdown 字符串 -->
    <vue-markdown>
      # 这是一个标题

      这是一个段落,支持 **加粗** 和 *斜体*。

      - 列表项 1
      - 列表项 2

    </vue-markdown>
  </div>
</template>

<script>
import VueMarkdown from 'vue-markdown'

export default {
  name: 'MarkdownDemo',
  components: {
    VueMarkdown
  }
}
</script>

<style scoped>
.markdown-demo {
  padding: 20px;
  border: 1px solid #ddd;
  border-radius: 8px;
  margin: 20px;
}
</style>

3.3 动态渲染

通过 v-model:source 属性动态渲染 Markdown:

vue 复制代码
<template>
  <div class="dynamic-markdown">
    <textarea v-model="markdownText" placeholder="输入 Markdown..." rows="10"></textarea>
    
    <h3>预览:</h3>
    <vue-markdown :source="markdownText" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      markdownText: '# 动态 Markdown\n\n实时预览你的输入。'
    }
  }
}
</script>

四、核心属性详解

vue-markdown 提供了丰富的属性来自定义渲染行为。

属性 类型 默认值 说明
source String '' 要渲染的 Markdown 源文本
tag String 'div' 外层包裹的 HTML 标签
html Boolean false 是否解析 Markdown 中的 HTML 标签
langPrefix String 'language-' 代码块语言的 CSS 类前缀
linkify Boolean true 将文本中的 URL 自动转换为链接
typographer Boolean false 启用一些语言相关的破折号替换
breaks Boolean false 转换 \n<br>
inline Boolean false 是否作为内联元素渲染(不包裹 <p>
anchorAttributes Object {} 为生成的锚点(<a>)添加自定义属性

示例:启用 HTML 和链接自动转换

vue 复制代码
<vue-markdown 
  :source="content" 
  :html="true" 
  :linkify="true"
  :breaks="true"
  tag="article">
</vue-markdown>

五、高级功能与扩展

5.1 自定义样式

vue-markdown 渲染出的 HTML 元素带有标准的语义化标签(h1, p, ul, pre code 等),你可以通过 CSS 轻松定制样式。

css 复制代码
/* 自定义 Markdown 样式 */
.vue-markdown h1 {
  color: #1890ff;
  border-bottom: 2px solid #eee;
}

.vue-markdown code {
  background: #f5f5f5;
  padding: 2px 4px;
  border-radius: 3px;
  font-family: 'Courier New', monospace;
}

.vue-markdown pre {
  background: #2b2b2b;
  color: #f8f8f2;
  padding: 16px;
  overflow: auto;
  border-radius: 6px;
}

.vue-markdown pre code {
  background: none;
  color: inherit;
  font-size: 14px;
}

5.2 扩展语法(使用 marked 配置)

虽然 vue-markdown 本身不直接暴露 marked 的所有配置,但你可以通过修改 marked 的全局设置来扩展功能。

javascript 复制代码
import marked from 'marked';

// 配置 marked
marked.setOptions({
  highlight: function(code, lang) {
    // 集成代码高亮(需引入 highlight.js)
    if (lang && window.hljs) {
      try {
        return window.hljs.highlight(lang, code).value;
      } catch (err) {
        console.error('Highlight error:', err);
      }
    }
    return code; // use external default escaping
  },
  // 其他选项...
});

然后在 vue-markdown 外部引入 highlight.js

html 复制代码
<!-- public/index.html -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>

5.3 安全性:防范 XSS 攻击

如果启用了 :html="true",用户输入的 HTML 可能包含恶意脚本(XSS)。强烈建议 对用户输入的内容进行严格的过滤或使用专门的库(如 DOMPurify)进行净化。

bash 复制代码
npm install dompurify
javascript 复制代码
import DOMPurify from 'dompurify';

// 在渲染前净化 HTML
const cleanHTML = DOMPurify.sanitize(dirtyHTML);

最佳实践 :除非必要,否则不要开启 :html="true"。对于用户生成内容,始终进行输入验证和输出净化。


六、实战案例:Markdown 编辑预览器

我们将构建一个完整的 Markdown 编辑器,支持实时预览。

6.1 项目结构

css 复制代码
src/
├── components/
│   ├── MarkdownEditor.vue
│   └── MarkdownPreview.vue
└── views/
    └── EditorView.vue

6.2 编辑器组件 (MarkdownEditor.vue)

vue 复制代码
<template>
  <textarea 
    v-model="content" 
    @input="onInput"
    class="markdown-editor"
    placeholder="输入 Markdown 语法..."
  ></textarea>
</template>

<script>
export default {
  name: 'MarkdownEditor',
  props: {
    value: String
  },
  data() {
    return {
      content: this.value || ''
    }
  },
  methods: {
    onInput() {
      this.$emit('input', this.content);
    }
  }
}
</script>

<style scoped>
.markdown-editor {
  width: 100%;
  height: 300px;
  padding: 12px;
  border: 1px solid #ddd;
  border-radius: 6px;
  font-family: 'Monaco', 'Consolas', monospace;
  resize: vertical;
}
</style>

6.3 预览组件 (MarkdownPreview.vue)

vue 复制代码
<template>
  <div class="markdown-preview">
    <vue-markdown 
      :source="source"
      :html="false"
      :breaks="true"
      :linkify="true"
    />
  </div>
</template>

<script>
import VueMarkdown from 'vue-markdown'

export default {
  name: 'MarkdownPreview',
  components: { VueMarkdown },
  props: {
    source: String
  }
}
</script>

<style scoped>
.markdown-preview {
  padding: 20px;
  border: 1px solid #eee;
  border-radius: 6px;
  background: #fff;
  min-height: 300px;
  /* 引入前面定义的 Markdown 样式 */
}
</style>

6.4 主视图 (EditorView.vue)

vue 复制代码
<template>
  <div class="editor-view">
    <h1>Markdown 实时编辑器</h1>
    
    <div class="editor-container">
      <div class="editor-pane">
        <h3>编辑</h3>
        <MarkdownEditor v-model="markdownContent" />
      </div>
      
      <div class="preview-pane">
        <h3>预览</h3>
        <MarkdownPreview :source="markdownContent" />
      </div>
    </div>
  </div>
</template>

<script>
import MarkdownEditor from '@/components/MarkdownEditor.vue'
import MarkdownPreview from '@/components/MarkdownPreview.vue'

export default {
  name: 'EditorView',
  components: {
    MarkdownEditor,
    MarkdownPreview
  },
  data() {
    return {
      markdownContent: `# 欢迎使用 Markdown 编辑器

## 功能列表

- **实时预览**
- 支持标准 Markdown 语法
- 代码块高亮(需配置)

\`\`\`javascript
function hello() {
  console.log("Hello, Markdown!");
}
\`\`\`

[访问 Vue 官网](https://vuejs.org)`
    }
  }
}
</script>

<style scoped>
.editor-view {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

.editor-container {
  display: flex;
  gap: 20px;
  margin-top: 20px;
}

.editor-pane, .preview-pane {
  flex: 1;
  border: 1px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
}

.editor-pane h3, .preview-pane h3 {
  margin: 0;
  padding: 10px;
  background: #f5f5f5;
  border-bottom: 1px solid #ddd;
}

.preview-pane {
  background: #fafafa;
}
</style>

参考资料

欢迎点赞、收藏、分享!如有疑问或建议,欢迎在评论区留言交流。

相关推荐
universe_015 分钟前
day25|学习前端js
前端·笔记
Zuckjet10 分钟前
V8 引擎的性能魔法:JSON 序列化的 2 倍速度提升之路
前端·chrome·v8
MrSkye10 分钟前
🔥React 新手必看!useRef 竟然不能触发 onChange?原来是这个原因!
前端·react.js·面试
wayman_he_何大民17 分钟前
初识机器学习算法 - AUM时间序列分析
前端·人工智能
juejin_cn18 分钟前
前端使用模糊搜索fuse.js和拼音搜索pinyin-match提升搜索体验
前端
....49242 分钟前
Vue3 + Element Plus 实现可搜索、可折叠、可拖拽的部门树组件
前端·javascript·vue.js
teeeeeeemo1 小时前
如何做HTTP优化
前端·网络·笔记·网络协议·http
范范之交1 小时前
JavaScript基础语法two
开发语言·前端·javascript
界面开发小八哥2 小时前
DevExtreme Angular UI控件更新:引入全新严格类型配置组件
前端·ui·界面控件·angular.js·devexpress
bitbitDown2 小时前
重构缓存时踩的坑:注释了三行没用的代码却导致白屏
前端·javascript·vue.js