歡迎光臨我的博客拓跋的前端客棧豆村,這個(gè)是原文地址剖踊,這個(gè)是項(xiàng)目地址,歡迎star&fork秦驯。如果您發(fā)現(xiàn)我文章中存在錯(cuò)誤,請(qǐng)盡情向我吐槽挣棕,大家一起學(xué)習(xí)一起進(jìn)步φ(>ω<*)
DEMO
最終效果請(qǐng)點(diǎn)擊這里译隘,是不是有點(diǎn)意思亲桥?
源碼分析
code-printer的原理是首先搭起一個(gè)骨架,然后通過遍歷的方式固耘,一點(diǎn)一點(diǎn)地往骨架里塞東西题篷。
骨架主要有三塊:
- <pre id="my-code">: 主要用來展示的HTML代碼的,帶標(biāo)簽
- <style id="style-elem">: 主要填CSS代碼的厅目,用于把<pre>里特定的標(biāo)簽轉(zhuǎn)換成特定的樣式
- <div id="script-area">: 主要是填JS代碼的番枚。但是由于一個(gè)字符一個(gè)字符往里面填代碼會(huì)出現(xiàn)大量報(bào)錯(cuò),因此這部分需要一個(gè)段落的JS代碼全部書寫完畢以后损敷,通過一個(gè)命令符'~'來一次性填入葫笼。
printCodes
let printCodes = function (message, index, interval) {
if (index < message.length) {
$code_pre.scrollTop = $code_pre.scrollHeight;
printChar(message[index++]);
return setTimeout((function () {
return printCodes(message, index, interval);
}), speed);
}
};
這段代碼的主要作用就是遍歷打印字符,同時(shí)每次打印的時(shí)候都將滾動(dòng)條拖到最底下拗馒,保證用戶能看到最新的變化路星。
printChar
let printChar = function (which) {
let char, formatted_code, prior_block_match, prior_comment_match, script_tag;
if (which === "`") {
// 重置為空字符串,防止打印出來
which = "";
isJs = !isJs;
}
if (isJs) {
if (which === "~" && !openComment) {
script_tag = createElement("script");
// two matches based on prior scenario
prior_comment_match = /(?:\*\/([^\~]*))$/;
prior_block_match = /([^~]*)$/;
if (unformatted_code.match(prior_comment_match)) {
script_tag.innerHTML = unformatted_code.match(prior_comment_match)[0].replace("*/", "") + "\n\n";
} else {
script_tag.innerHTML = unformatted_code.match(prior_block_match)[0] + "\n\n";
}
$script_area.innerHTML = "";
$script_area.appendChild(script_tag);
}
char = which;
formatted_code = jsHighlight($code_pre.innerHTML, char);
} else {
char = which === "~" ? "" : which;
$style_elem.innerHTML += char;
formatted_code = cssHighlight($code_pre.innerHTML, char);
}
prevAsterisk = which === "*";
prevSlash = (which === "/") && !openComment;
openInteger = which.match(/[0-9]/) || (openInteger && which.match(/[\.\%pxems]/)) ? true : false;
if (which === '"') {
openString = !openString;
}
unformatted_code += which;
return $code_pre.innerHTML = formatted_code;
};
printChar函數(shù)是code-printer的核心函數(shù)诱桂,這個(gè)函數(shù)會(huì)根據(jù)當(dāng)前的代碼是JS還是CSS洋丐,來進(jìn)行不同的處理。
如何判斷是JS還是CSS代碼呢挥等?默認(rèn)設(shè)置
let isJs = false;
也就是默認(rèn)是CSS友绝,然后以 ` 作為切換符號(hào),每次遇到 ` 就切換一次語言肝劲。
當(dāng)前字符屬于JS時(shí)九榔,在沒遇到執(zhí)行符號(hào) ~ 之前,printChar只是單純的打印格式化后的字符涡相。遇到 ~ 以后哲泊,printChar進(jìn)行了如下操作:
- 函數(shù)首先通過正則匹配,匹配出之前的JS整段代碼催蝗。
- 再調(diào)用createElement()來創(chuàng)造一對(duì)<script></script>標(biāo)簽切威,用來存放JS代碼。
- 然后將處理過的JS代碼存入<script></script>標(biāo)簽內(nèi)丙号。
- 最后通過$script_area.appendChild()的方式將<script></script>及其內(nèi)部的JS代碼存入<div id="script-area">中先朦。注意,每次調(diào)用$script_area.appendChild()之前犬缨,都要將之前<div id="script-area">清空一遍喳魏,防止之前的JS代碼再執(zhí)行一次。
當(dāng)前字符屬于CSS時(shí)怀薛,每次打印過程刺彩,一方面會(huì)將未格式化的字符串傳入<style id="style-elem">中,用以生成樣式。另一方面會(huì)將格式化的代碼輸出到<pre id="my-code">中创倔,用以展示代碼嗡害。
cssHighlight和jsHighlight
這兩個(gè)函數(shù)十分類似,主要作用就是通過正則匹配畦攘,給不同類型的字符兩端封上不同的標(biāo)簽霸妹,用以高亮代碼。舉個(gè)栗子:
if (openInteger && !which.match(/[0-9\.]/) && !openString && !openComment) {
s = string.replace(/([0-9\.]*)$/, "<em class=\"int\">$1</em>" + which);
}
這就是一處典型的匹配+替換標(biāo)簽組合拳知押。作用是代碼在以數(shù)字結(jié)尾時(shí)叹螟,給數(shù)字兩端封上<em class="int"></em>的標(biāo)簽。
代碼中還有很多用作標(biāo)志位的參數(shù)台盯,比如說openInteger罢绽,表示這段輸入都是數(shù)字。通過對(duì)這些控制位進(jìn)行操作爷恳,可以將零散的字符分成一段一段的有缆,方便進(jìn)行處理。
其他部分就不談了温亲,自己可以看源代碼棚壁,我已經(jīng)加了備注。
使用方法
您可以fork過去直接修改栈虚,也可以按照如下步驟操作
git clone https://github.com/tuobaye0711/code-printer.git
安裝依賴文件
npm install
打包文件
npm start
起服務(wù)
npm run server
修改配置說明:
resume 文件存放簡歷或者其他靜態(tài)資源
source/code.js 存放需要打印并展示樣式的代碼(CSS/JS)
source/app.js 是主代碼袖外,可以修改一些比如說打印速度、高亮色等配置
小結(jié)
能在自己網(wǎng)站掛一份帶打印特效的簡歷魂务,想必能讓人眼前一亮吧曼验。這篇文章主要安利了一下我這個(gè)名為code-printer的小項(xiàng)目,希望能幫到各位~