博客网页代码块渲染-显示行号,一键复制,全屏显示,mac风格(基于mavon-editor或wangEditor)

效果预览

在这里插入图片描述
在这里插入图片描述

亮点:mac风格代码块,一键复制,全屏浏览,点击按住文字空白区域可左右滑动(感觉有待优化),双击关闭全屏浏览。。。。。。

样式可自行优化

前提条件(待渲染的代码块格式)

<pre>
	<code >
		print("hello world")
		print("我是醉瑾”)
	</code>
</pre>

code为pre的直接子元素,code除了代码文本无直接子元素。pre元素不需要任何类名,实际上wangEditor的编辑器输出中代码块格式就是这样的(好像很多都是这样),mavonEditor默认输出就带有语法高亮(输出时就设置了高亮样式等,但不符合我们的需要,此时设置mavonEditor的ishljs属性为false,输出格式就是上面所说的格式,具体如下

<!-- MarkDown 编辑器 -->
        <!-- 禁止代码高亮,为后期自定义代码块样式方便 -->
        <div class="editor-mavon-editor">
            <mavon-editor
                ref="md"
                class="mavon-editor"
                v-show="!richText"
                v-model="markContent"
                code-style="vs2015"
                :ishljs="false"
                @save="save"
                @imgAdd="imgAdd"
                @change="markOnChange">
            </mavon-editor>
        </div>

有关富文本编辑器使用请自行百度

本次实践基于vue,但是和普通html写法大同小异,代码如下:

<template>
    <!-- 文章 -->
    <div id="article">
        <div class="markdown-body" v-html="article.content"></div>
    </div>
</template>

<script>
import {getArt} from '@/api/article';
import 'mavon-editor/dist/markdown/github-markdown.min.css';
// https://blog.csdn.net/weixin_43664308/article/details/108508966
import hljs from 'mavon-editor/dist/highlightjs/highlight.min.js';
import 'mavon-editor/dist/highlightjs/styles/github-dark-dimmed.min.css';

export default {
    name: 'Article',
    data() {
        return {
            article: {},
        };
    },
    async mounted() {
        const id = this.$route.query.id;
        if (id != null || id !== undefined) {
            let result = await getArt(id);
            if (result['code'] === 200) {
                // console.log('获取到的文章为:', result.data);
                this.article = result.data;
            }
        }
        this.$nextTick(() => {
            const code = document.querySelectorAll('pre code');
            code.forEach((item) => {
                // 取出 code 的父元素 pre(后面方便使用)
                let pre = item.parentElement;

                // 添加拖动属性
                this.dragAround(item);

                // 新建元素 代码块序号
                let lineNumBox = document.createElement('div');
                lineNumBox.setAttribute('style', 'height: ' + item.offsetHeight + 'px');
                lineNumBox.className = 'line-num-box';
                // 插入序号 计算方式:获取code元素的高并除以行高,得到行数,根据行数插入序号
                let num = '';  // 设行高二十
                for (let i = 1; i <= Math.ceil(item.offsetHeight / 20); i++) {
                    num += i + '\n'; // 序号加上换行符
                }
                lineNumBox.innerText = num;// 插入序号
                item.parentElement.insertBefore(lineNumBox, item);

                let codeBox = document.createElement('div');
                codeBox.className = 'code-box';
                codeBox.appendChild(item);

                pre.appendChild(codeBox);

                let lang = pre.lastElementChild.firstElementChild.className;
                let icon = `<div class="mac-icon">` +
                    `<span class="mac-icon-red"></span>` +
                    `<span class="mac-icon-yellow"></span>` +
                    `<span class="mac-icon-green"></span>` +
                    `<span class="mac-icon-lang">${lang.split('-')[1].toUpperCase()}</span>` +
                    `<button class="copy-button">复制</button>` +
                    `<button class="full-screen-button">全屏</button>` +
                    `</div>`;
                pre.insertAdjacentHTML('afterbegin', icon);

                // 获取复制元素
                let copyButton = pre.firstElementChild.getElementsByClassName('copy-button')[0];
                copyButton.onclick = function () {
                    // https://developer.mozilla.org/zh-CN/docs/Web/API/Clipboard/writeText
                    const copyPromise = navigator.clipboard.writeText(pre.lastElementChild.innerText);
                    copyPromise.then(() => {
                        alert('复制成功');
                    }).catch(() => {
                        alert('复制失败');
                    });
                };

                // 获取全屏按钮元素
                let fullScreenButton = pre.firstElementChild.getElementsByClassName('full-screen-button')[0];
                fullScreenButton.onclick = function () {
                    // 此写法基于 pre 元素没有其他任何类名的情况下
                    if (pre.className === 'pre-full-screen') {
                        this.innerText = '全屏';
                        pre.className = '';
                        pre.setAttribute("title","");
                    } else {
                        this.innerText = '关闭';
                        pre.className = 'pre-full-screen';
                        pre.setAttribute("title","双击关闭全屏");
                    }
                };
                // 双击关闭全屏
                pre.ondblclick = function () {
                    fullScreenButton.innerText = '全屏';
                    // 此写法基于 pre 元素没有其他任何类名的情况下
                    this.className = '';
                    pre.setAttribute("title","");
                };
                hljs.highlightBlock(codeBox.firstElementChild);
            });
        });
    },
    methods: {
        // 给某个元素添加左右拖动属性
        dragAround(anyElement) {
            let mouseDown = false; // 鼠标是否按下
            let x = 0; // 鼠标点击的下标
            let left = 0; // 当前滚动条位置
            anyElement.onmousedown = function (e) {
                mouseDown = true;       // 鼠标按下
                x = e.clientX;          // 获取鼠标点击位置 (x坐标)
                left = this.scrollLeft; // 滚动条当前位置
            };
            anyElement.onmousemove = function (e) {
                // 鼠标按下
                if (mouseDown) {
                    let curX = e.clientX; // 鼠标移动到当前的位置
                    let diffX = curX - x; // 鼠标移动距离(当前位置 减去之前的位置)
                    this.scrollLeft = left - diffX;
                }
            };
            anyElement.onmouseup = function () {
                mouseDown = false;
            };
            anyElement.onmouseleave = function () {
                mouseDown = false;
            };
        },
    },
};
</script>

<style scoped>
#article {
    width: 100%;
}

>>> pre {
    border: 1px solid red;
    background-color: #1e1e1e !important;
    border-radius: 15px !important;
}

/* 自定义全屏样式 */
>>> .pre-full-screen {
    position: fixed;
    left: 0 !important;
    top: 0 !important;
    width: 100vw !important;
    z-index: 100;
    height: 100vh !important;
}

>>> .line-num-box {
    display: inline-block;
    color: white;
    border-right: 2px solid white;
    line-height: 20px !important;
    font-size: 16px !important;
    text-align: right;
    padding-left: 10px;
    padding-right: 10px;
}

>>> .code-box {
    display: inline-block;
    vertical-align: top;
    width: calc(100% - 50px);
    border-left-style: none;
}

/*滚动条样式 https://m.php.cn/article/475268.html*/
>>> code {
    line-height: 20px !important;
    font-size: 16px !important;
    vertical-align: top;
    padding-top: 0 !important;
    padding-bottom: 0 !important;
    padding-left: 10px !important;
}

>>> code::-webkit-scrollbar{/*滚动条整体样式*/
    /*width: 100px !important;*/
    height: 10px;
    border-radius: 5px;
    background-color: green;
}

>>> code::-webkit-scrollbar-thumb{/*滚动条里面小方块*/
    border-radius: 5px;
    background-color: wheat;
}

>>> code::-webkit-scrollbar-button{/*滚动条的轨道的两端按钮,允许通过点击微调小方块的位置*/
    border-radius: 5px;
    background-color: yellow;
}

>>> .mac-icon {
    border-bottom: 1px solid silver;
    margin-bottom: 5px;
    color: deeppink;
}

>>> .mac-icon > span {
    display: inline-block;
    letter-spacing: 5px;
    word-spacing: 5px;
    width: 16px;
    height: 16px;
    border-radius: 8px;
}

>>> .mac-icon-red {
    background-color: red;
}

>>> .mac-icon-yellow {
    margin-left: 10px;
    background-color: yellow;
}

>>> .mac-icon-green {
    margin-left: 10px;
    background-color: green;
}

>>> .mac-icon-lang {
    width: 50px !important;
    padding-left: 10px;
    font-size: 16px;
    vertical-align: top;
}

>>> .copy-button, >>> .full-screen-button {
    width: 40px;
    height: 20px;
    background-color: wheat;
    margin-bottom: 3px;
    border-radius: 5px;
    outline: none;
    border: none;
}

>>> .full-screen-button {
    width: 40px !important;
    height: 20px;
}

>>> .copy-button {
    /*
        减去padding 2*16(如果使box-sizing: border-box;则不用减去),
        减去图标 3*16
        图标间隙 10*2
        语言 宽度 50px
        减去本身宽 40px
        全屏按钮 margin-left 10px
        全屏按钮宽 40px
    */
    margin-left: calc(100% - 208px);
}

>>> .full-screen-button {
    margin-left: 10px;
}

>>> .copy-button:hover, >>> .full-screen-button:hover {
    background-color: white;
}
</style>

import 'mavon-editor/dist/markdown/github-markdown.min.css';
// https://blog.csdn.net/weixin_43664308/article/details/108508966
import hljs from 'mavon-editor/dist/highlightjs/highlight.min.js'; // 可按需引入
import 'mavon-editor/dist/highlightjs/styles/github-dark-dimmed.min.css'; 

以上引入为mavon-editor集成的,直接引入使用(项目使用mavon-editor的情况下,否则需要自行安装 highlight.min.js。

mac风格代码块

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

心醉瑶瑾前

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

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

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

打赏作者

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

抵扣说明:

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

余额充值