vue3:基于highlight实现代码高亮、显示代码行数、添加复制功能

前言

在vscode中,有代码高亮的功能。那么如果在前端项目中,展示代码时如何实现高亮效果。

这是我们可以使用highlight.jshighlight.js是一款基于JavaScript的语法高亮库,它具有以下功能:
在这里插入图片描述
备注:关于复制的方法execCommand已经废弃了,我懒得改了,替代方式见:前端复制、剪切、禁止复制等

highlight官网

使用

安装

## 这个是highlight.js基础依赖
npm install --save highlight.js
## 安装支持vue3 的@highlightjs/vue-plugin 依赖
npm install --save @highlightjs/vue-plugin

main.js引入

// highlight 的样式,依赖包,组件
import 'highlight.js/styles/atom-one-dark.css'
import 'highlight.js/lib/common'
import hljsVuePlugin from '@highlightjs/vue-plugin'

//注册组件
app.use(hljsVuePlugin)

使用

<template>
    <div>
         <highlightjs language="JavaScript" :autodetect="false" :code="code"></highlightjs>
    </div>
</template>

<script setup lang="ts">
let code = 'import { createApp } from "vue";import App from "./App.vue";'

</script>

<style scoped lang="scss">
</style>

注意:

  • 因为插件不支持响应式数据,所以不要使用ref定义响应式变量
  • autodetect 将自动匹配设置为false,自动匹配一般不准

比较常用的语言有:HTMLXMLC++CSSJavaJavaScriptPHPPythonSCSSSQLTypeScript其他语言可以自行查看官方文档

效果
在这里插入图片描述

修改样式

更换主题

现在我们使用的主题是:

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

在这里插入图片描述
可以根据官方demo,找到一个自己喜欢的主题。然后引入就好,如何引用呢?找到highlight.js/styles文件夹,引入对应的样式即可,我这里用的这个androidstudio,感觉不错

import 'highlight.js/styles/androidstudio.css'

自定义样式

到目前为止,还是不太好看,我想要的是这样的
在这里插入图片描述
这里可以自己写一些样式来实现

<template>
    <div class="hljs-container" codetype="JavaScript">
        <highlightjs language="JavaScript" :autodetect="false" :code="code"></highlightjs>
    </div>
</template>

<script setup lang="ts">
let code = `let a = 1;import hljs-containerVuePlugin from '@highlightjs/vue-plugin';import hljs-containerVuePlugin from '@highlightjs/vue-plugin';
import hljs-containerVuePlugin from '@highlightjs/vue-plugin';
import hljs-containerVuePlugin from '@highlightjs/vue-plugin';`;
</script>

<style scoped lang="scss">
/* 语法高亮 */
.hljs-container {
    position: relative;
    display: block;
    width: 600px;
    padding: 30px 5px 2px;
    overflow-x: hidden;
    line-height: 20px;
    text-align: left;
    background: #21252b;
    box-shadow: 0 10px 30px 0 rgb(0 0 0 / 40%);
}

/** 3个点 */
.hljs-container::before {
    position: absolute;
    top: 10px;
    left: 15px;
    width: 12px;
    height: 12px;
    overflow: visible;
    font-weight: 700;
    font-size: 16px;
    line-height: 12px;
    white-space: nowrap;
    text-indent: 75px;
    background-color: #fc625d;
    border-radius: 16px;
    box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
    content: attr(codetype);
}

/** 滚动条 */
:deep(.hljs) {
    overflow-x: auto;
}

:deep(.hljs::-webkit-scrollbar) {
    width: 12px !important;
    height: 12px !important;
}

:deep(.hljs::-webkit-scrollbar-thumb) {
    height: 30px !important;
    background: #d1d8e6;
    background-clip: content-box;
    border: 2px solid transparent;
    border-radius: 19px;
    opacity: 0.8;
}

:deep(.hljs::-webkit-scrollbar-thumb:hover) {
    background: #a5b3cf;
    background-clip: content-box;
    border: 2px solid transparent;
}

:deep(.hljs::-webkit-scrollbar-track-piece) {
    width: 30px;
    height: 30px;
    background: #333;
}

::-webkit-scrollbar-button {
    display: none;
}
</style>

在这里插入图片描述

功能

需要添加 代码行数点击复制的功能

效果

在这里插入图片描述

完整代码

组件

<template>
    <div class="hljs-container" codetype="JavaScript" v-code>
        <highlightjs language="JavaScript" :autodetect="false" :code="code"></highlightjs>
    </div>
</template>

<script setup lang="ts">
import vCode from './line';
let code = `let a = 1;
import hljs-containerVuePlugin from '@highlightjs/vue-plugin';
import hljs-containerVuePlugin from '@highlightjs/vue-plugin';
<div class="hljs-container" codetype="JavaScript" v-code>
    <highlightjs language="JavaScript" :autodetect="false" :code="code"></highlightjs>
</div>`;
</script>

<style scoped lang="scss">
@import "./code.scss";
</style>

指令

import './code.scss';
const vCode = {
    mounted(el: any) {
        //获取代码片段
        let code = el.querySelector('code.hljs')
        let pre = document.getElementsByTagName('pre')[0]
        let html = code?.innerHTML
        let size = html.split('\n').length

        //插入行数
        let ul = document.createElement('ul')
        for (let i = 1; i <= size; i++) {
            let li = document.createElement('li')
            li.innerText = i + ''
            ul.appendChild(li)
        }

        ul.classList.add('hljs-code-number')

        el.insertBefore(ul, pre)

        //插入复制功能
        let copy = document.createElement('div')
        copy.classList.add('hljs-copy')
        copy.innerText = '复制'
        //添加点击事件
        copy.addEventListener('click', () => {
            //创建一个输入框
            let textarea = document.createElement('textarea')
            document.body.appendChild(textarea);
            textarea.setAttribute('readonly', 'readonly')
            textarea.value = code.innerText;
            textarea.select();
            if (document.execCommand('copy')) {
                document.execCommand('copy');
                copy.innerText = '复制成功'
            }
            document.body.removeChild(textarea);
        })

        pre.appendChild(copy)

        //鼠标移入显示复制按钮
        el.addEventListener('mouseout', () => {
            copy.innerText = '复制'
            copy.style.display = "none"
        })
        el.addEventListener('mouseover', () => {
            copy.style.display = "block"

        })
    }
}

export default vCode

样式

/* 语法高亮 */
.hljs-container {
    position: relative;
    display: block;
    display: flex;
    width: max-content;
    margin-left: 100px;
    padding: 30px 10px 2px 0;
    overflow-x: hidden;
    font-size: 14px;
    line-height: 24px;
    text-align: left;
    background: #21252b;
    box-shadow: 0 10px 30px 0 rgb(0 0 0 / 40%);
}

/** 3个点 */
.hljs-container::before {
    position: absolute;
    top: 10px;
    left: 15px;
    width: 12px;
    height: 12px;
    overflow: visible;
    font-weight: 700;
    font-size: 16px;
    line-height: 12px;
    white-space: nowrap;
    text-indent: 75px;
    background-color: #fc625d;
    border-radius: 16px;
    box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
    content: attr(codetype);
}

/** 滚动条 */
:deep(.hljs) {
    overflow-x: auto;
}

:deep(.hljs::-webkit-scrollbar) {
    width: 12px !important;
    height: 12px !important;
}

:deep(.hljs::-webkit-scrollbar-thumb) {
    height: 30px !important;
    background: #d1d8e6;
    background-clip: content-box;
    border: 2px solid transparent;
    border-radius: 19px;
    opacity: 0.8;
}

:deep(.hljs::-webkit-scrollbar-thumb:hover) {
    background: #a5b3cf;
    background-clip: content-box;
    border: 2px solid transparent;
}

:deep(.hljs::-webkit-scrollbar-track-piece) {
    width: 30px;
    height: 30px;
    background: #333;
}

::-webkit-scrollbar-button {
    display: none;
}

/** 行数样式 */
.hljs-code-number {
    padding: 17px 10px 0;
    color: #d1d8e6;
    font-size: 12px;
    list-style: none;
    border-right: 1px solid #d1d8e6;
}

/** 复制样式 */
.hljs-copy {
    position: absolute;
    top: 50px;
    right: 30px;
    display: none;
    padding: 0 10px;
    color: #66a9ff;
    font-size: 10px;
    background-color: #ecf5ff;
    border-radius: 3px;
    cursor: pointer;
}
Vue 3 可以通过自定义指令 (Directive) 和 Marked 库来实现代码一键复制功能。 下面是实现的基本步骤: 1. 安装 Marked 库 ```bash npm install marked ``` 2. 创建一个自定义指令 在 Vue 3 中,自定义指令可以通过 `app.directive` 方法来创建。下面是一个创建 `copy-code` 指令的示例代码: ```javascript import marked from &#39;marked&#39;; const copyCodeDirective = { mounted(el, binding) { const code = el.querySelector(&#39;code&#39;); const button = document.createElement(&#39;button&#39;); button.innerText = &#39;Copy&#39;; button.addEventListener(&#39;click&#39;, () => { navigator.clipboard.writeText(code.textContent.trim()); button.innerText = &#39;Copied!&#39;; setTimeout(() => { button.innerText = &#39;Copy&#39;; }, 2000); }); el.appendChild(button); }, updated(el) { const code = el.querySelector(&#39;code&#39;); const html = marked(code.textContent); code.innerHTML = html; } }; export default copyCodeDirective; ``` 这个自定义指令会在绑定的元素上添加一个 "Copy" 按钮,并且当用户点击按钮时,会将元素内部的代码文本复制到剪贴板中。 3. 在组件中使用自定义指令 ```html <template> <pre v-copy-code><code>{{ code }}</code></pre> </template> <script> import copyCodeDirective from &#39;./copyCodeDirective.js&#39;; export default { directives: { copyCode: copyCodeDirective }, data() { return { code: &#39;console.log("Hello, world!");&#39; } } }; </script> ``` 在组件中,我们可以将 `v-copy-code` 指令绑定到 `<pre>` 标签上,然后将代码文本插入到 `<code>` 标签中。 当我们在浏览器中运行这个组件时,就会看到代码旁边出现一个 "Copy" 按钮。当我们点击该按钮时,代码文本就会被复制到剪贴板中。 希望这个示例能够帮助您实现您的功能
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无知的小菜鸡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值