JS生成可自定义语法高亮HTMLcode

cnblogs @ Orcim   



!deprecated!

这里有更好的方案,具体看我的这篇博客博客代码高亮的另一种思路


这篇文章介绍了如何在博客里插入一段 pretty 代码框的方法(以博客园为例),主要是因为实在是受不了博客园以及其他一些博客自带代码框的样子了w~

这篇文章很长很长,你可以直接点击这里,直接跳到源代码处,复制代码,或者滑到文章最底部查看使用方法。

原 理是利用 VSCode Copy With Syntax Highlighting 这个自带的功能,其实很多 IDE 都具有此类功能:

Ctrl + 逗号,打开设置,搜索找到上图中的选项就可以开启高亮语法复制为 HTML 代码的这个功能了,当然现在直接粘贴并不能直接获取到 剪切板内 TEXT 文本,也无法获取带高亮样式的内 HTML 文本。

其实是可以获取剪切板的 HTML 文本的,js 提供了一个 onpaste 事件,可以在函数事件的 event 参数中获取到剪切板的内容了。

event.clipboardData.getData( Format: String )

如果要获取剪切板的纯文本,String 为 “text/plan”,如果是 HTML 文本,String 为 “text/html”:

 
CODE01.js
12345
document.onpaste = function (e){
    var cb_data = e.clipboardData.getData("text\/html");
    // var cb_data = e.clipboardData.getData("text\/plain");
    console.log(cb_data);
}
 

然后,在 IDE 里面复制一段高亮显示着的代码,浏览器里面 Ctrl + V,控制台会 log 出来一堆东西:

为方便查看把这串从 VSCode剪切板 里面得到的内容 Prettify 一下,其实很有规律:

 
CODE02.html
12345678910111213141516171819
<!--StartFragment-->
<div style="color: #d4d4d4;background-color: #1e1e1e;font-family: Meslo LG L DZ, Microsoft YaHei;font-weight: 200;font-size: 16px;line-height: 34px;white-space: pre;">
    <div>
        <span style="color: #9cdcfe;">document</span>
        <span style="color: #d4d4d4;">.</span>
        <span style="color: #dcdcaa;">onpaste</span>
        <span style="color: #d4d4d4;"> = </span>
        <span style="color: #569cd6;">function</span>
        <span style="color: #d4d4d4;"> (</span>
        <span style="color: #9cdcfe;">e</span>
        <span style="color: #d4d4d4;">){</span>
    </div>
    <div>
        <span style="color: #d4d4d4;">    </span>
        <span style="color: #569cd6;">var</span>
        ........
    </div>
</div>
<!--EndFragment-->
 

可能你也发现了规律了吧,其实这就是大多数 IDE 的语法高亮显示功能的原理,整个编辑器就相当于浏览器的窗口,窗口中每段文字都被特定样式的标签包裹起来……每行一个 div 又包裹很多 span 的行内元素,就这样一行一行堆砌,然后就实现了这个功能。

得到的这些 HTML 文本基本上就可以复制到各大博客的编辑器来用了,但是我们除了去设置整个编辑器的样式这个方法之外,没有其他更简便的办法去改变高亮的样式了,而且如果剪切板中 HTML 标签内为 制表符或者是一些空白字符的话,编辑器通常会将其忽略,就没有代码缩进显示,比如我在博客园的编辑器中直接复制 CODE02 的代码到 HTML 编辑文本域里面,代码的缩进全部都没有了,于是就想到对这些剪切板里面的内容处理一下,可以灵活输出自己想要展示 Code 的 HTML。

于是花了一天的时间,从最初的 HTML模板布局 到整个功能的实现,以及 JS 代码修改,最后完善了整个程序。直接给大家看 demo,其实前面的代码框就是演示……,上面的两个代码展示框就是 JS 生成的(普通的字符串的处理),加入了行数标识以及标题标识功能,之后还添加了一个 light 主题,两者样式兼容移动端:

 
theme.js
12345678910111213141516
var themes = {
    "dark": {
        c_title_bg: "#252525", 
        c_title_fg: "#ededed",
        c_editor_bg: "#1e1e1e",
        c_sideNum_bg: "#1e1e1e",
        c_sideNum_fg: "#727272"
    }, 
    "light": {
        c_title_bg: "#dcdcdc", 
        c_title_fg: "#999",
        c_editor_bg: "#f5f5f5",
        c_sideNum_bg: "#e5e5e5",
        c_sideNum_fg: "#999"
    }
};
 

这里就不卖关子了,直接贴代码吧,里面有注释。

-(紧凑的分割线)-

源代码

HTML 代码,便于最后的自定义样式的代码框输出

 
copyAsHTML.html
12345678910111213141516171819202122232425262728293031323334353637
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>CopyAsHtmlFromVScode</title>
</head>
<body>
    <div id="codePart">
        <div id="codeBox" style='width: 100%; height: auto; line-height: 34px; position: relative; font-family: "Meslo LG L DZ", "monospace";'>
            <!-- 标题一栏 -->
            <div id="banner" style="width: 100%; height: 34px; position: absolute; top: 0; left: 0; background: rgba(0, 0, 0, .1); border-top-left-radius: 8px; border-top-right-radius: 8px; box-sizing: border-box; border-bottom: 1px solid rgba(0, 0, 0, .15)">
                <!-- 
                    生成的代码框左上角用于标识文件类型的圆,颜色集合变量名:stampColors
                    html -> 红
                    css -> 蓝
                    js -> 黄
                    txt -> 黑灰
                 -->
                <div id="bannerStamp" style="height: 34px; width: 34px; float: left; display: flex; align-items: center; justify-content: center"><span style="display: block; width: 60%; height: 60%; -webkit-border-radius: 50%; background: green">&nbsp;</span></div>
                <!-- 标题名 -->
                <div style="height: 34px; float: left; font-size: 16px; line-height: 34px; display: flex; align-items: center;"><span style="display: block; font-family: sans-serif" id="bannerTitle">123.html</span></div>
            </div>
            <div class="side" id="vsSide" style="width: 50px; background: none; float: left; padding: 40px 0 30px; background: #f5f5f5; border-top-left-radius: 8px; border-bottom-left-radius: 8px;">
                <!-- 侧边行数一列 -->
            </div>
            <div id="containerOuter" style="width: calc(100% - 70px); float: left; white-space: nowrap; background: #f5f5f5; overflow: auto; padding: 40px 0 30px 20px; border-bottom-right-radius: 8px; border-top-right-radius: 8px;">
                <!-- 代码高亮的展示 HTML -->
                <div id="_containerBox"></div>
            </div>
                <!-- 防止高度坍塌 -->
            <div style="clear: both;"></div>
        </div>
    </div>
</body>
</html>
 

JS 代码,直接复制放在 body 标签后的 script 标签里面,这里分开展示是为了方便排版和阅读~

 
copyAsHTML.js
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
var themes = { // 主题,自己定义了两种,可以自己加~
    "dark": {
        c_title_bg: "#252525", // 标题栏背景色
        c_title_fg: "#ededed", // 前景色(文字颜色)
        c_editor_bg: "#1e1e1e", // 代码区背景
        c_sideNum_bg: "#1e1e1e", // 行数栏背景
        c_sideNum_fg: "#727272" // 前景色
    }, 
    "light": {
        c_title_bg: "#dcdcdc", 
        c_title_fg: "#999",
        c_editor_bg: "#f5f5f5",
        c_sideNum_bg: "#e5e5e5",
        c_sideNum_fg: "#999"
    }
};
var config = { // 调整基本样式
    "theme": "dark", // 主题名
    "fontFamily": '"Meslo LG L DZ", "monospace"', 
    "lineHeight": "25px",
    "fontSize": "15px",
    "fileName": "copyAsHTML.js", // 标题名称
    "stampColor": "" // 留空会根据文件拓展名设置圆点的颜色
};
document.onpaste = function(e){
    format(); // 初始化代码外框模板
    var cb_str = e.clipboardData.getData('text\/html'); // 获取从 VSCode 里面复制的含 html 标签的代码
    var tmpDiv = document.createElement("div");
    tmpDiv.innerHTML = cb_str;
    var containerBox = tmpDiv.children[0];
 
    var arrLineDiv = containerBox.children;
    var HollowArr = [];
    for(var i=0; i<arrLineDiv.length; i++){
        var arrLineSpanChar = arrLineDiv[i].children;
        var tmp_arrLine = [];
        for(var j=0; j<arrLineSpanChar.length; j++){
            var arrEmpty = [];
            arrEmpty[0] = arrLineSpanChar[j].style.color;
            // 空格替换为 HTML 转义符
            arrEmpty[1] = arrLineSpanChar[j].innerHTML.replace(/ /g, "&nbsp;");
            tmp_arrLine.push(arrEmpty);
        }
        HollowArr.push(tmp_arrLine);
    }
 
    var _containerBox = document.getElementById("_containerBox");
    var _sideNums = document.getElementById("vsSide");
    for(var l=0; l<HollowArr.length; l++){
        _containerBox.append(returnLine(HollowArr[l]));
        var tmpSpan = returnSpan("", l+1);
        tmpSpan.style = "display: block; width: 40px; text-align: right; padding-right: 10px; float: left; font-size: 14px; height: " + config.lineHeight;
        _sideNums.append(tmpSpan);
    }
    var g_Span = _sideNums.querySelectorAll("span");
    if(_sideNums.innerHTML) g_Span[g_Span.length - 1].style.borderBottomRightRadius = "4px";
    // 最终结果在浏览器控制台处输出查看
    console.log(document.getElementById("codePart").innerHTML); 
 
    function returnLine(array){
        var oDiv = document.createElement("div");
        oDiv.style = "height: " + config.lineHeight + "; line-height: " + config.lineHeight + "; font-size: " + config.fontSize + ";";
        for(var k=0; k<array.length; k++){
            tspan = returnSpan(array[k][0], array[k][1]);
            tspan.style.lineHeight = "100%";
            oDiv.append(tspan);
        }
        var groupSpan = oDiv.querySelectorAll("span");
        if(oDiv.innerHTML) groupSpan[groupSpan.length - 1].style.paddingRight = "20px";
        return oDiv;
    }
    function returnSpan(cr, ct){
        var oSpan = document.createElement("span");
        oSpan.innerHTML = ct;
        if(!cr) return oSpan;
        oSpan.style.color = cr;
        return oSpan;
    } 
    function format(){
        var stampColors = { // 左上角圆点颜色主题集合
            "html": "#d13239", 
            "css": "#4286f4", 
            "js": "#fbb507", 
            "txt": "#303030", 
        }
        var oCodeBox = document.getElementById("codeBox");
        var oBanner = document.getElementById("banner");
        var bannerStamp = document.getElementById("bannerStamp");
        var bannerTitle = document.getElementById("bannerTitle");
        var oVsSide = document.getElementById("vsSide");
        var oOuter = document.getElementById("containerOuter");
        var theStampColor = config.stampColor;
        var configTheme = config.theme;
 
        if(!config.stampColor) theStampColor = stampColors[config.fileName.split(".").pop()];
        oCodeBox.style.fontFamily = config.fontFamily;
        oCodeBox.style.lineHeight = config.lineHeight;
        bannerTitle.innerText = config.fileName;
        bannerStamp.querySelector("span").style.backgroundColor = theStampColor;
        oBanner.style.backgroundColor = themes[configTheme].c_title_bg;
        bannerTitle.style.color = themes[configTheme].c_title_fg;
        oOuter.style.backgroundColor = themes[configTheme].c_editor_bg;
        oVsSide.style.backgroundColor = themes[configTheme].c_sideNum_bg;
        oVsSide.style.color = themes[configTheme].c_sideNum_fg;
    }
}
 

使用方法

  1. 在 copyAsHTML.html 中引入 copyAsHTML.js
  2. 打开 VSCode,并在设置中确保已勾选 控制在复制时是否同时复制语法高亮 选项
  3. Ctrl + C 复制一段编辑器的代码
  4. Chrome 打开 copyAsHTML.html,页面空白区 Ctrl + V 粘贴
  5. F12 打开 控制台,Copy 输出的所有内容
  6. 粘贴 HTML 代码到 HTML 编辑器中,即可

Advance

添加复制功能和展开/收起功能:

 
advancedHighLight.html
COPY EXPAND
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>CopyAsHtmlFromVScode</title>
    <style>
    </style>
</head>
<body>
    <div id="codePart">
        <div id="codeBox" class="codeBox" style='width: 100%; height: auto; line-height: 34px; position: relative; font-family: "Meslo LG L DZ", "monospace";'>
            <div id="banner" class="banner" style="width: 100%; height: 34px; position: absolute; top: 0; left: 0; background: rgba(0, 0, 0, .1); border-top-left-radius: 8px; border-top-right-radius: 8px; box-sizing: border-box; border-bottom: 1px solid rgba(0, 0, 0, .15)">
                <div id="bannerStamp" style="height: 34px; width: 34px; float: left; display: flex; align-items: center; justify-content: center">
                    <span style="display: block; width: 60%; height: 60%; border-radius: 50%; background: green">&nbsp;</span>
                </div>
                <div style="height: 34px; float: left; font-size: 16px; line-height: 34px; display: flex; align-items: center;">
                    <span style="display: block; font-family: sans-serif" id="bannerTitle">123.html</span>
                </div>
                <div style="height: 34px; float: right; font-size: 16px; line-height: 34px; display: flex; align-items: center; justify-content: center;">
                    <span style="display: block; background: rgba(255, 255, 255, .65); font-family: sans-serif; padding: 0 5px; margin-right: 10px;" data-clipboard-target="">COPY</span>
                    <span class="expandBtn" style="display: block; background: rgba(255, 0, 0, .65); color: #f5f5f5; font-family: sans-serif; padding: 0 5px; margin-right: 10px;">EXPAND</span>
                </div>
            </div>
            <div class="side" id="vsSide" style="width: 50px; background: none; float: left; padding: 40px 0 30px; background: #f5f5f5; border-top-left-radius: 8px; border-bottom-left-radius: 8px;">
            </div>
            <div id="containerOuter" style="width: calc(100% - 70px); float: left; white-space: nowrap; background: #f5f5f5; overflow: auto; padding: 40px 0 30px 20px; border-bottom-right-radius: 8px; border-top-right-radius: 8px;">
                <div id="_containerBox">
 
                </div>
            </div>
            <div style="clear: both;">
            </div>
        </div>
    </div>
</body>
</html>
<script src="./clipBoard.js"></script>
<script>
var themes = { // 主题,自己定义了两种,可以自己加~
    "dark": {
        c_title_bg: "#252525", // 标题栏背景色
        c_title_fg: "#ededed", // 前景色(文字颜色)
        c_editor_bg: "#1e1e1e", // 代码区背景
        c_sideNum_bg: "#1e1e1e", // 行数栏背景
        c_sideNum_fg: "#727272" // 前景色
    }, 
    "light": {
        c_title_bg: "#dcdcdc", 
        c_title_fg: "#999",
        c_editor_bg: "#f5f5f5",
        c_sideNum_bg: "#e5e5e5",
        c_sideNum_fg: "#999"
    }
};
var config = { // 调整基本样式
    "theme": "dark", // 主题名
    "fontFamily": '"Meslo LG L DZ", "monospace"', 
    "lineHeight": "25px",
    "fontSize": "15px",
    "fileName": "advancedHighLight.html", // 标题名称
    "stampColor": "", // 留空会根据文件拓展名设置圆点的颜色
    "maxHeight": 400, // 限制高度,px
    "highLight": [true, "#569cd6"]
};
 
/* 兼容 IE, getComputedStyle */
if (!window.getComputedStyle) {
    window.getComputedStyle = function(el, pseudo) {
        this.el = el;
        this.getPropertyValue = function(prop) {
            var re = /(\-([a-z]){1})/g;
            if (prop == 'float') prop = 'styleFloat';
            if (re.test(prop)) {
                prop = prop.replace(re, function () {
                    return arguments[2].toUpperCase();
                });
            }
            return el.currentStyle[prop] ? el.currentStyle[prop] : null;
        }
        return this;
    }
};
document.onpaste = function(e){
    format(); // 初始化代码外框模板
    var cb_str = e.clipboardData.getData('text\/html') || e.clipboardData.getData('text\/plain'); // 获取从 VSCode 里面复制的含 html 标签的代码
    console.log(cb_str)
    var tmpDiv = document.createElement("div");
    tmpDiv.innerHTML = cb_str;
    var containerBox = tmpDiv.children[0];
 
    var arrLineDiv = containerBox.children;
    var HollowArr = [];
    for(var i=0; i<arrLineDiv.length; i++){
        var arrLineSpanChar = arrLineDiv[i].children;
        var tmp_arrLine = [];
        for(var j=0; j<arrLineSpanChar.length; j++){
            var arrEmpty = [];
            arrEmpty[0] = arrLineSpanChar[j].style.color;
            // 空格替换为 HTML 转义符
            arrEmpty[1] = arrLineSpanChar[j].innerHTML.replace(/ /g, "&nbsp;");
            tmp_arrLine.push(arrEmpty);
        }
        HollowArr.push(tmp_arrLine);
    }
 
    var _containerBox = document.getElementById("_containerBox");
    var stamp = new Date().getTime();
    _containerBox.id = "d" + stamp;
    document.querySelector("[data-clipboard-target]").dataset.clipboardTarget = "#d" + stamp;
    var _sideNums = document.getElementById("vsSide");
    for(var l=0; l<HollowArr.length; l++){
        _containerBox.append(returnLine(HollowArr[l]));
        var tmpSpan = returnSpan("", l+1);
        tmpSpan.style = "display: block; width: 40px; text-align: right; padding-right: 10px; float: left; font-size: 14px; height: " + config.lineHeight;
        _sideNums.append(tmpSpan);
    }
    var g_Span = _sideNums.querySelectorAll("span");
    if(_sideNums.innerHTML) g_Span[g_Span.length - 1].style.borderBottomRightRadius = "4px";
    
    var cb = document.getElementById("codeBox");
    var codeHeight = parseFloat(window.getComputedStyle(codeBox, "").getPropertyValue("height"));
    console.log(codeHeight)
    var expandBtn = document.querySelector(".expandBtn");
    var tog = {
        "expand": function(){
            document.getElementById("banner").style.borderTopRightRadius = "8px";
            // cb.style.maxHeight = codeHeight + "px";
            cb.style.overflow = "auto";
            return "SHRINK";
        },
        "shrink": function(){
            document.getElementById("banner").style.borderTopRightRadius = 0;
            // cb.style.maxHeight = config.maxHeight + "px";
            cb.style.overflow = "auto";
            return "EXPAND";
        }
    };
    if(codeHeight > config.maxHeight){
        expandBtn.style.display = "block";
        tog["shrink"]();
        expandBtn.onclick = function(){
            var lbl = this.innerHTML;
            this.innerHTML = (lbl === "EXPAND" ? tog["expand"]() : tog["shrink"]());
        }
    }else{
        expandBtn.style.display = "none";
    }
    // 最终结果在看控制台处输出查看
    console.log(document.getElementById("codePart").innerHTML); 
 
    function returnLine(array){
        var oDiv = document.createElement("div");
        var bFill = config.highLight[0];
        oDiv.style = "height: " + config.lineHeight + "; line-height: " + config.lineHeight + "; font-size: " + config.fontSize + ";";
        if(!bFill) oDiv.style.color = config.highLight[1];
        for(var k=0; k<array.length; k++){
            tspan = returnSpan(array[k][0], array[k][1], bFill);
            tspan.style.lineHeight = "100%";
            oDiv.append(tspan);
        }
        var groupSpan = oDiv.querySelectorAll("span");
        if(oDiv.innerHTML) groupSpan[groupSpan.length - 1].style.paddingRight = "20px";
        return oDiv;
    }
    function returnSpan(cr, ct, fill = true){
        var oSpan = document.createElement("span");
        oSpan.innerHTML = ct;
        if(!cr) return oSpan;
        if(fill) oSpan.style.color = cr;
        return oSpan;
    } 
    function format(){
        var stampColors = { // 左上角圆点颜色主题集合
            "html": "#d13239", 
            "css": "#4286f4", 
            "js": "#fbb507", 
            "txt": "#373a41", 
            "plist": "#8bc34a"
        }
        var oCodeBox = document.getElementById("codeBox");
        var oBanner = document.getElementById("banner");
        var bannerStamp = document.getElementById("bannerStamp");
        var bannerTitle = document.getElementById("bannerTitle");
        var oVsSide = document.getElementById("vsSide");
        var oOuter = document.getElementById("containerOuter");
        var theStampColor = config.stampColor;
        var configTheme = config.theme;
 
        if(config.maxHeight){
            oCodeBox.dataset.maxHeight = config.maxHeight;
        };
        if(!config.stampColor) theStampColor = stampColors[config.fileName.split(".").pop()];
        oCodeBox.style.fontFamily = config.fontFamily;
        oCodeBox.style.lineHeight = config.lineHeight;
        bannerTitle.innerText = config.fileName;
        bannerStamp.querySelector("span").style.backgroundColor = theStampColor;
        oBanner.style.backgroundColor = themes[configTheme].c_title_bg;
        bannerTitle.style.color = themes[configTheme].c_title_fg;
        oOuter.style.backgroundColor = themes[configTheme].c_editor_bg;
        oVsSide.style.backgroundColor = themes[configTheme].c_sideNum_bg;
        oVsSide.style.color = themes[configTheme].c_sideNum_fg;
    }
}
new ClipboardJS('[data-clipboard-target]');
 
</script>
 

Advance Ver2.0

增加代码框盒子bottom处的复制按钮和展开/收起按钮。

 
advancedHighLight_ver_2_0.html
COPY EXPAND
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>CopyAsHtmlFromVScode</title>
    <style>
    </style>
</head>
<body>
    <div id="codePart">
        <div id="codeBox" class="codeBox" style='width: 100%; height: auto; line-height: 34px; position: relative; font-family: "Meslo LG L DZ", "monospace";'>
            <div id="banner" class="banner" style="width: 100%; height: 34px; position: absolute; top: 0; left: 0; background: rgba(0, 0, 0, .1); border-top-left-radius: 8px; border-bottom-left-radius: 8px; box-sizing: border-box; border-bottom: 1px solid rgba(0, 0, 0, .15)">
                <div id="bannerStamp" style="height: 34px; width: 34px; float: left; display: flex; align-items: center; justify-content: center">
                    <span style="display: block; width: 60%; height: 60%; border-radius: 50%; background: green">&nbsp;</span>
                </div>
                <div style="height: 34px; float: left; font-size: 16px; line-height: 34px; display: flex; align-items: center;">
                    <span style="display: block; font-family: sans-serif" id="bannerTitle">123.html</span>
                </div>
                <div style="height: 34px; float: right; font-size: 16px; line-height: 34px; display: flex; align-items: center; justify-content: center;">
                    <span style="display: block; background: rgba(255, 255, 255, .65); font-family: sans-serif; padding: 0 5px; margin-right: 10px;" data-clipboard-target="">COPY</span>
                    <span class="expandBtn" style="display: block; background: rgba(255, 0, 0, .65); color: #f5f5f5; font-family: sans-serif; padding: 0 5px; margin-right: 10px;">EXPAND</span>
                </div>
            </div>
            <div class="side" id="vsSide" style="width: 50px; background: none; float: left; padding: 40px 0 45px; background: #f5f5f5; border-top-left-radius: 8px; border-bottom-left-radius: 8px;">
            </div>
            <div id="containerOuter" style="width: calc(100% - 70px); float: left; white-space: nowrap; background: #f5f5f5; overflow: auto; padding: 40px 0 45px 20px; border-bottom-right-radius: 8px; border-top-right-radius: 8px;">
                <div id="_containerBox">
 
                </div>
            </div>
            <div class="banner" style="width: 100%; height: 34px; position: absolute; bottom: 55px; left: 0; box-sizing: border-box; border-bottom: 1px solid rgba(0, 0, 0, .15)">
                <div style="height: 34px; float: right; font-size: 16px; line-height: 34px; display: flex; align-items: center; justify-content: center;">
                    <span style="display: block; background: rgba(255, 255, 255, .65); font-family: sans-serif; padding: 0 5px; margin-right: 10px;" data-clipboard-target="">COPY</span>
                    <span class="expandBtn" style="display: block; background: rgba(255, 0, 0, .65); color: #f5f5f5; font-family: sans-serif; padding: 0 5px; margin-right: 10px;">EXPAND</span>
                </div>
            </div>
            <div style="clear: both;">
            </div>
        </div>
    </div>
</body>
</html>
<script src="./clipBoard.js"></script>
<script>
var themes = { // 主题,自己定义了两种,可以自己加~
    "dark": {
        c_title_bg: "#252525", // 标题栏背景色
        c_title_fg: "#ededed", // 前景色(文字颜色)
        c_editor_bg: "#1e1e1e", // 代码区背景
        c_sideNum_bg: "#1e1e1e", // 行数栏背景
        c_sideNum_fg: "#727272" // 前景色
    }, 
    "light": {
        c_title_bg: "#dcdcdc", 
        c_title_fg: "#999",
        c_editor_bg: "#f5f5f5",
        c_sideNum_bg: "#e5e5e5",
        c_sideNum_fg: "#999"
    }
};
var config = { // 调整基本样式
    "theme": "dark", // 主题名
    "fontFamily": '"Meslo LG L DZ", "monospace"', 
    "lineHeight": "25px",
    "fontSize": "15px",
    "fileName": "advancedHighLight_ver_2_0.html", // 标题名称
    "stampColor": "", // 留空会根据文件拓展名设置圆点的颜色
    "maxHeight": 400, // 限制高度,px
    "highLight": [true, "#569cd6"]
};
 
/* 兼容 IE, getComputedStyle */
if (!window.getComputedStyle) {
    window.getComputedStyle = function(el, pseudo) {
        this.el = el;
        this.getPropertyValue = function(prop) {
            var re = /(\-([a-z]){1})/g;
            if (prop == 'float') prop = 'styleFloat';
            if (re.test(prop)) {
                prop = prop.replace(re, function () {
                    return arguments[2].toUpperCase();
                });
            }
            return el.currentStyle[prop] ? el.currentStyle[prop] : null;
        }
        return this;
    }
};
document.onpaste = function(e){
    format(); // 初始化代码外框模板
    var cb_str = e.clipboardData.getData('text\/html') || e.clipboardData.getData('text\/plain'); // 获取从 VSCode 里面复制的含 html 标签的代码
    console.log(cb_str)
    var tmpDiv = document.createElement("div");
    tmpDiv.innerHTML = cb_str;
    var containerBox = tmpDiv.children[0];
 
    var arrLineDiv = containerBox.children;
    var HollowArr = [];
    for(var i=0; i<arrLineDiv.length; i++){
        var arrLineSpanChar = arrLineDiv[i].children;
        var tmp_arrLine = [];
        for(var j=0; j<arrLineSpanChar.length; j++){
            var arrEmpty = [];
            arrEmpty[0] = arrLineSpanChar[j].style.color;
            // 空格替换为 HTML 转义符
            arrEmpty[1] = arrLineSpanChar[j].innerHTML.replace(/ /g, "&nbsp;");
            tmp_arrLine.push(arrEmpty);
        }
        HollowArr.push(tmp_arrLine);
    }
 
    var _containerBox = document.getElementById("_containerBox");
    var stamp = new Date().getTime();
    _containerBox.id = "d" + stamp;
    var clipBoard_tars = document.querySelectorAll("[data-clipboard-target]");
    for(var c=0; c<clipBoard_tars.length; c++) clipBoard_tars[c].dataset.clipboardTarget = "#d" + stamp;
    var _sideNums = document.getElementById("vsSide");
    for(var l=0; l<HollowArr.length; l++){
        _containerBox.append(returnLine(HollowArr[l]));
        var tmpSpan = returnSpan("", l+1);
        tmpSpan.style = "display: block; width: 40px; text-align: right; padding-right: 10px; float: left; font-size: 14px; height: " + config.lineHeight;
        _sideNums.append(tmpSpan);
    }
    var g_Span = _sideNums.querySelectorAll("span");
    if(_sideNums.innerHTML) g_Span[g_Span.length - 1].style.borderBottomRightRadius = "4px";
    
    var cb = document.getElementById("codeBox");
    var codeHeight = parseFloat(window.getComputedStyle(codeBox, "").getPropertyValue("height"));
    console.log(codeHeight)
    var expandBtn = document.querySelector(".expandBtn");
    var tog = {
        "expand": function(){
            document.getElementById("banner").style.borderTopRightRadius = "8px";
            // cb.style.maxHeight = codeHeight + "px";
            cb.style.overflow = "auto";
            return "SHRINK";
        },
        "shrink": function(){
            document.getElementById("banner").style.borderTopRightRadius = 0;
            // cb.style.maxHeight = config.maxHeight + "px";
            cb.style.overflow = "auto";
            return "EXPAND";
        }
    };
    if(codeHeight > config.maxHeight){
        expandBtn.style.display = "block";
        tog["shrink"]();
        expandBtn.onclick = function(){
            var lbl = this.innerHTML;
            this.innerHTML = (lbl === "EXPAND" ? tog["expand"]() : tog["shrink"]());
        }
    }else{
        expandBtn.style.display = "none";
    }
    // 最终结果在看控制台处输出查看
    console.log(document.getElementById("codePart").innerHTML); 
 
    function returnLine(array){
        var oDiv = document.createElement("div");
        var bFill = config.highLight[0];
        oDiv.style = "height: " + config.lineHeight + "; line-height: " + config.lineHeight + "; font-size: " + config.fontSize + ";";
        if(!bFill) oDiv.style.color = config.highLight[1];
        for(var k=0; k<array.length; k++){
            tspan = returnSpan(array[k][0], array[k][1], bFill);
            tspan.style.lineHeight = "100%";
            oDiv.append(tspan);
        }
        var groupSpan = oDiv.querySelectorAll("span");
        if(oDiv.innerHTML) groupSpan[groupSpan.length - 1].style.paddingRight = "20px";
        return oDiv;
    }
    function returnSpan(cr, ct, fill = true){
        var oSpan = document.createElement("span");
        oSpan.innerHTML = ct;
        if(!cr) return oSpan;
        if(fill) oSpan.style.color = cr;
        return oSpan;
    } 
    function format(){
        var stampColors = { // 左上角圆点颜色主题集合
            "html": "#d13239", 
            "css": "#4286f4", 
            "js": "#fbb507", 
            "txt": "#373a41", 
            "plist": "#8bc34a"
        }
        var oCodeBox = document.getElementById("codeBox");
        var oBanner = document.getElementById("banner");
        var bannerStamp = document.getElementById("bannerStamp");
        var bannerTitle = document.getElementById("bannerTitle");
        var oVsSide = document.getElementById("vsSide");
        var oOuter = document.getElementById("containerOuter");
        var theStampColor = config.stampColor;
        var configTheme = config.theme;
 
        if(config.maxHeight){
            oCodeBox.dataset.maxHeight = config.maxHeight;
        };
        if(!config.stampColor) theStampColor = stampColors[config.fileName.split(".").pop()];
        oCodeBox.style.fontFamily = config.fontFamily;
        oCodeBox.style.lineHeight = config.lineHeight;
        bannerTitle.innerText = config.fileName;
        bannerStamp.querySelector("span").style.backgroundColor = theStampColor;
        oBanner.style.backgroundColor = themes[configTheme].c_title_bg;
        bannerTitle.style.color = themes[configTheme].c_title_fg;
        oOuter.style.backgroundColor = themes[configTheme].c_editor_bg;
        oVsSide.style.backgroundColor = themes[configTheme].c_sideNum_bg;
        oVsSide.style.color = themes[configTheme].c_sideNum_fg;
    }
}
new ClipboardJS('[data-clipboard-target]');
 
</script>
COPY EXPAND
 

Copy As HTML From VSCode的更多相关文章

  1. 编写一个Open Live Writer的VSCode代码插件

    起因 又是一年多没有更新过博客了,最近用Arduino做了一点有意思的东西,准备写一篇博客.打开尘封许久的博客园,发现因为Windows Live Writer停止更新,博客园推荐的客户端变为了Ope ...

  2. HEC-ResSim原文档

              HEC-ResSim Reservoir System Simulation             User's Manual       Version 3.1 May 201 ...

  3. shift Alt + up(down) copy current line ! ctrl + j show the control # vscode key

    shift Alt + up(down) copy current line ! ctrl + j show the control # vscode key

  4. vscode restclient 插件

    使用步骤: 1.vscode 安装restclient 扩展 2.创建  .http 或 .rest 文件 ,编写相应内容 同一个文件内 可以通过 ### 分割多个请求 可以通过 @hostname ...

  5. vscode之常用快捷键

    原文章地址: vscode: Visual Studio Code 常用快捷键 官方快捷键说明:Key Bindings for Visual Studio Code 主命令框 F1 或 Ctrl+S ...

  6. vscode c++ cmake template project

    VSCode configure C++ dev environment claim use CMake to build the project. For debugging, VSCode's C ...

  7. vscode 集成 cygwin 的注意事项

    vscode 集成 cygwin vscode 现在是我的主力开发编辑器,它自带 terminal 不需要我各种切换,我还想要在 windows 下执行一些简单的 .sh 文件.所以,我希望有一款工具 ...

  8. win10 添加项目右键用vscode打开

    1.新建reg文件:在vscode安装目录下新建一个文本文件,然后将文件后缀改为:*.reg,文件名任意,例如:vsCodeOpenFolder.reg. 2.编写文本文件内容.将下面的内容Copy到 ...

  9. 使用VSCode调试单个PHP文件

    突然发现是可以使用 VSCode 调试单个 PHP 文件的,今天之前一直没有弄成功,还以为 VSCode 是不能调试单文件呢.这里记录一下今天这个"突然发现"的过程. 开始,是在看 ...

随机推荐

  1. JVM系列.历史上出现过的Java虚拟机

    HotSpot绝对是当今商用虚拟机的王者,但是在Java历史上出现过很多Java虚拟机,这篇文章就来整理下历史上出现过的Java虚拟机以及他们的特性. Sun Classic Sun Classic虚 ...

  2. 你不得不知的Java基础知识

    本篇博客主要记录Java中面向对象的概念和Java语法的基础知识. 面向对象 什么是面向对象 面向对象是一种优秀的软件设计思想,是相对于面向过程.面向切面等设计思想的一种软件设计理念.它的核心思想是运 ...

  3. Java 后端开发常用的 10 种第三方服务

    请肆无忌惮地点赞吧,微信搜索[沉默王二]关注这个在九朝古都洛阳苟且偷生的程序员.本文 GitHub github.com/itwanger 已收录,里面还有我精心为你准备的一线大厂面试题. 严格意义上 ...

  4. pytest allure 生成html测试报告

    前提:需要 java 1.8 以上.python3环境 一.下载pytest pip install pytest 二.下载Allure Pytest Adaptor插件 pip install py ...

  5. 《Java从入门到失业》第四章:类和对象(4.1):初识类和对象

    4类和对象 在第一章曾经简单介绍过,在面向对象的世界里,一切事物皆对象,当解决一个问题的时候,我们先会考虑这个问题会涉及到哪些事物,然后把事物抽象成类,当时还画了一张图如下: 从本章开始,我们一点一点 ...

  6. jmeter的用途

    1.可以测接口 2.测试连数据库 3.可以进行压测 4.可部署分布式

  7. [补题]求a[i]+a[j]+i-j的最大值,要求i<j

    题目 如题. 例: 输入: 5 11 6 5 18 12 输出: 29 题解 思路: 一直是按着(a[i]+a[j])+(i-j)想后序的思路,不应该限制住自己,应该多考虑拆的方法.正确思路是把a[i ...

  8. Docker实战(6): 导出docker镜像离线包

    前言 离线环境安装Docker 镜像,我已知两种情况,以下操作我将采用在可访问外网的机器上通过镜像迁移的方式来给离线环境安装. 环境:服务器node1可访问外网.服务器node2无法访问外网 两台机器 ...

  9. 常用的CSS命名规范大总结

    转载: http://www.php.cn/toutiao-417563.html 文本命名规范 index.css: 一般用于首页建立样式 head.css: 头部样式,当多个页面头部设计风格相同时 ...

  10. Envoy 代理中的请求的生命周期

    Envoy 代理中的请求的生命周期 翻译自Envoy官方文档. 目录 Envoy 代理中的请求的生命周期 术语 网络拓扑 配置 高层架构 请求流 总览 1.Listener TCP连接的接收 2.监听 ...