《如何用 Vue 2 和 Highlight.js 打造一个优雅的代码展示组件》

299 阅读2分钟

1. 依赖引入

  • 安装 Highlight.js:

    npm install highlight.js
    
  • 注册 HTML 语言包(按需引入减少体积):

    import hljs from 'highlight.js/lib/core';
    import html from 'highlight.js/lib/languages/xml';
    hljs.registerLanguage('html', html);
    

2. 代码高亮方法

  • 核心方法highlightHtml(htmlContent)

    • 使用 hljs.highlight() 解析 HTML 内容。
    • 返回高亮后的 HTML 字符串。
    highlightHtml(htmlContent) {
      const highlighted = hljs.highlight(htmlContent, { language: 'html' }).value;
      return highlighted;
    }
    

3. 动态内容处理

  • 注入机制:通过 inject: ["detailData"] 接收父组件传递的 html_content内容字段

  • 生命周期:在 mounted 阶段处理数据,确保 DOM 已渲染。

    mounted() {
      const htmlContent = this.detailData.data.html_content || '';
      this.highlightedCode = this.highlightHtml(htmlContent);
    }
    

4. 样式优化

  • 保留格式:通过 white-space: pre-wrap 和 word-wrap: break-word 实现长代码换行。

  • 响应式overflow: auto 防止代码块撑开容器。

  • 视觉优化

    • 背景色、圆角、边框增强可读性。
    • 字体设置为等宽字体(monospace)。
    pre {
      margin: 0;
      padding: 16px;
      background-color: #f5f5f5;
      border: 1px solid #ddd;
      border-radius: 4px;
      overflow: auto;
      white-space: pre-wrap;
      word-wrap: break-word;
    }
    

四、关键问题与解决方案

1. 长代码换行

  • 问题:默认情况下,长代码会横向溢出,破坏布局。

  • 解决

    pre {
      white-space: pre-wrap; /* 保留换行符但允许换行 */
      word-wrap: break-word; /* 允许单词内换行 */
    }
    

2. 动态内容更新

  • 问题:如果 html_content 是异步加载,mounted 可能无法捕获最新数据。

  • 解决:添加 watch 监听数据变化:

    watch: {
      detailData: {
        handler(newVal) {
          const htmlContent = newVal.data.html_content || '';
          this.highlightedCode = this.highlightHtml(htmlContent);
        },
        deep: true, // 深度监听
      },
    },
    

3. 扩展其他语言

  • 步骤

    1. 引入其他语言包(如 JavaScript):

      import javascript from 'highlight.js/lib/languages/javascript';
      hljs.registerLanguage('javascript', javascript);
      
    2. 动态切换语言:

      highlightHtml(content, language) {
        return hljs.highlight(content, { language }).value;
      }
      

五、性能优化

  1. 按需引入语言包:仅注册需要的语言(如 HTML、JavaScript、CSS)。
  2. 防抖处理:如果代码块频繁更新,使用 lodash.debounce 减少重渲染。
  3. 虚拟滚动:超大型代码块使用 vue-virtual-scroller 优化性能。

六、完整代码示例

父组件调用

<template>
  <div>
    <CodeHighlighter :detailData="yourDataObject" />
  </div>
</template>

<script>
import CodeHighlighter from './CodeHighlighter.vue';
export default {
  components: { CodeHighlighter },
  data() {
    return {
      yourDataObject: {
        data: {
          html_content: '<div class="example">Hello World</div>',
        },
      },
    };
  },
};
</script>

组件代码

<template>
  <div>
    <pre class="hljs"><code v-html="highlightedCode"></code></pre>
  </div>
</template>

<script>
import hljs from 'highlight.js/lib/core';
import 'highlight.js/styles/github.css';
import html from 'highlight.js/lib/languages/xml';
hljs.registerLanguage('html', html);

export default {
  inject: ["detailData"],
  data() {
    return { highlightedCode: '' };
  },
  mounted() {
    const htmlContent = this.detailData.data.html_content || '';
    this.highlightedCode = this.highlightHtml(htmlContent);
  },
  methods: {
    highlightHtml(htmlContent) {
      const highlighted = hljs.highlight(htmlContent, { language: 'html' }).value;
      return highlighted;
    },
  },
};
</script>

<style scoped>
pre {
  margin: 0;
  padding: 16px;
  background-color: #f5f5f5;
  border: 1px solid #ddd;
  border-radius: 4px;
  overflow: auto;
  white-space: pre-wrap;
  word-wrap: break-word;
}
pre code {
  font-family: 'Courier New', monospace;
  font-size: 14px;
}
</style>

七、总结

适用场景

  • 文档系统(如 VuePress、Docusaurus)
  • 博客平台(代码片段高亮)
  • 开发者工具(如在线 IDE、调试面板)

优势

  • 开箱即用:5 行代码即可实现基础高亮。
  • 高度可定制:支持语言扩展、主题切换。
  • 性能友好:按需加载,无冗余依赖。