溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何將JavaScript 代碼裝扮成圣誕樹

發(fā)布時間:2021-11-17 10:21:51 來源:億速云 閱讀:235 作者:柒染 欄目:web開發(fā)

如何將JavaScript 代碼裝扮成圣誕樹,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

其實(shí)也不神奇,我們使用了自己寫的一個nodejs庫,如果您要實(shí)現(xiàn)這樣的效果,只需要按照下面的方法即可。

下面分兩章節(jié),分別講解如何使用js2image這個庫 和 js2image這個庫的原理。

  • github地址:https://github.com/xinyu198736/js2image ps:求star

  • 在線轉(zhuǎn)換地址:http://f2e.souche.com/cheniu/js2image.html

如何將JavaScript 代碼裝扮成圣誕樹

js2image使用

github地址:https://github.com/xinyu198736/js2image 歡迎送上star或者follow。

js2image主要有兩個比較特殊的特性:

  1. 將任意js源碼 壓縮成 用代碼堆砌成圖形的最終代碼。例如圣誕樹,圣誕老人,代碼和圖片都可以自定義。

  2. 壓縮后的js代碼格式雖然被破壞,但是仍然可以運(yùn)行。這個是關(guān)鍵點(diǎn)!

壓縮后的示例可以查看這些js(均來自搜車官網(wǎng)):

  • http://assets.souche.com/assets/js/souche.js souche主腳本

  • http://assets.souche.com/assets/js/lib/jquery-1.7.1.min.js jquery 1.7.1

  • http://assets.souche.com/assets/js/lib/mustache.js mustache

使用方式很簡單:

npm install js2image -g;

然后在存在js的文件夾中執(zhí)行:

js2image -s ./resource/jquery.js

或者針對某個目錄下所有的js執(zhí)行(慎用),會深度遍歷此目錄里所有的js文件然后壓縮出.xmas.js后綴的結(jié)果文件。

js2image -s ./resource/

即可生成一個對應(yīng)的 **.xmas.js 的文件。

如果要將js2image集成到gulp或者其他nodes項(xiàng)目中,可以使用用模塊的形式:

var Js2Image = require("js2image");//獲取結(jié)果的    codeJs2Image.getCode("./resource/jquery.js","./resource/tree.png",  {}).then(function(code){     console.log(code); })

更多的信息可以參照github上的文檔。

如果只是要使用這個效果,看到這里就ok啦,下面講解這個庫的原理,有些地方可能比較繞。

js2image實(shí)現(xiàn)原理

js2image的實(shí)現(xiàn)從宏觀來說,大體只有3個要點(diǎn)。

  1. 從圖片生成字符畫,這個有現(xiàn)成的庫。

  2. 把js代碼分割成一小塊一小塊,盡量小,然后用逐行填充的方式分別替換到上一步生成的字符畫里去。

  3. js代碼中有諸多不能分開的語法,分塊的時候要把這些語法保留在一個塊內(nèi)。這個是這個庫的難點(diǎn)所在,也是代碼最多最繞的地方。

稍有想法的同學(xué)估計看到這里基本已經(jīng)明白是怎么回事了,下面一一講解這3個要點(diǎn)。

① 從圖片生成2值得字符畫

這里用到了一個現(xiàn)成的npm包:image-to-ascii 。這個庫的作用是用指定的字符來還原一個圖像。而我們用這個庫來生成一個用  ?字符和空格  分別表示黑和白的字符畫,然后將字符畫的每一行分解成數(shù)組的一個元素,供第二步使用,這就是我們中間生成的一個struct,代碼見 utils/image-to-struct.js

② 分割js源碼成盡量小的小塊。

這是非常重要的一步,js代碼具體可以分解成多細(xì)的小塊呢?

看下面一段代碼:

                        !function                                     (e,t                                     ){ (                                    "objec"                                 +"t")  ==                                typeof                              module &&  (                           "objec"+"t")                           == typeof module                       .exports?module.                   exports=e.document?t(e                 ,!0):function(e){if(!e.             document) throw new Error (           ("jQuer"+"y req"+"uires"+" a wi"      +"ndow "+"with "+"a doc"+"ument") )   ; return t (e)}:t(e)}( ("undef"+"ined") !=typeof    window ?window:this,function(e,t){var

這是jQuery開始的一段代碼,可以看到,大部分操作符都允許中間插入任意多的空格或者換行,我們正是利用這一特性將js代碼解肢,然后拼接成任意形狀的圖片。

核心代碼其實(shí)就是一個正則,我們用這個正則把js源碼解構(gòu)成一個數(shù)組,然后后續(xù)根據(jù)每行需要的字符數(shù),從這個數(shù)組里不斷取片段出來拼接。

//分離代碼,以可分割單位拆分成數(shù)組。var lines = hold_code.replace(/([^a-zA-Z_0-9=!|&$])/g,"/n$1/n").split("/n"); //有了這個lines數(shù)組之后后面就簡單了,根據(jù)***步里生成的struct不斷遍歷從lines抽取代碼填充到struct里即可生成最終的代碼: while(lines.length>0){      //循環(huán)往struct里填充代碼     struct.forEach(function(s){         var chars_arr = s.replace(/ +/g," ");//一行有多組分離的*****         var r = s;         chars_arr.split(/ +/).forEach(function(chars){             if(chars.length == 0){                 return;             }             var char_count = chars.length;             //從lines里取出char_count數(shù)量的代碼來填充,不一定精準(zhǔn),要確保斷行正確             var l = pickFromLines(lines,char_count);              r = r.replace(chars,function(){                 return l;             })         })         result += r+"/n"     })  }

③ 保留不可分割的語法

注意:到了這一步,還很早,你分解出來的代碼是無法運(yùn)行的,很多不能換行和加空格的代碼都被你分開了,自然會報錯,那如何處理這些情況呢?

這一步,我們做的工作就是:

在執(zhí)行代碼分拆之前,提取出代碼里所有不可分割的語法,將他們保留在一個對象中,并且在源代碼中用占位符替代這些語法,然后讓占位符參與上個步驟的分離,因?yàn)檎嘉环且粋€完整的連字符變量,所以不會被分割。在分割完成之后,我們再把這些占位符替換回來即可。

不過,在js中哪些語法必須是連接在一起才能正常運(yùn)行的呢?

這里總結(jié)下:

  1. 字符串不可分割 包括雙引號單引號內(nèi)的內(nèi)容。

  2. 正則表達(dá)式絕對不可分割 正則里的轉(zhuǎn)義很難處理,這是這個算法里的難點(diǎn)。

  3. 運(yùn)算操作符 包括2字符的3字符的 例如 以下兩種

var double_operator = ["==", ">=", "<=", "+=", "-=", "*=", "/=", "%=", "++", "--", "&&", "||", ">>", "<<"]  var three_operator = ['===', '!==']

一些固定語法,可以用正則表達(dá),如下:

var reg_operator = [      {         start:"return",         reg:/^return[^a-zA-Z_0-1"'][a-zA-Z_0-1.]+/         // return 0.1 或者 return function 或者return aaabb     },     {         start:"return/"",         reg:/^return".*?"/ // return "d" 或者 return ""     },     {         start:"return/'",         reg:/^return'.*?'/  // return 'd' 或者 return ''     },     {         start:"throw",         reg:/^throw [a-zA-Z_0-1]+?/ //throw new 或者 throw obj     } ]

小數(shù)點(diǎn)語法,例如 0.01 因?yàn)橹拔覀冇命c(diǎn)號來分割代碼的,但是這里的點(diǎn)號不能作為分割符使用,需要保留前后數(shù)字跟點(diǎn)號在一行 其他語法,例如 value++ 之類的語法,變量和操作符之間不可分割。 那我們?nèi)绾螐脑创a中解析出這些語法,然后做處理呢?

核心代碼均在 utils/keep-line.js 中

核心算法,事實(shí)上是通過一個對字符串的遍歷來完成的,然后在遍歷每個字符的時候都會判斷是否進(jìn)入某個邏輯來跳躍處理。

例如,判斷出當(dāng)前在雙引號內(nèi),則進(jìn)入字符串提取邏輯,一直到字符串結(jié)束的時候再繼續(xù)正常的遍歷。

其他操作符和正則表達(dá)式的算法也是類似,不過里面很多細(xì)節(jié)需要處理,例如轉(zhuǎn)義字符之類的。

有些比較特殊的,例如小數(shù)點(diǎn)語法的提取,在判斷到當(dāng)前字符是點(diǎn)號之后,需要往前和向后循環(huán)查找數(shù)字,然后把整個語法找出來。

這里不細(xì)講,在keep-line.js 這個文件中又一大坨代碼做這個事情的。

④ 字符串解構(gòu)

做到這一步的時候,其實(shí)效果已經(jīng)很不錯了,也可以保證代碼的可運(yùn)行,但是代碼里有些字符串很長,他們總是會被被保留在一行里,這樣就造成他會影響一些圖案的邊緣的準(zhǔn)確性(代碼分離原則是越細(xì)越好,就是為這個考慮)。

我們?nèi)绾翁幚砟?,那就是將字符串解?gòu),以5個為單位將字符串分離成小塊。

這里有兩個比較重要的問題需要處理;

  1. 字符串內(nèi)的轉(zhuǎn)義字符如何處理,還有一些特殊字符,例如0&times;01這樣的字符,這些字符不能被分離到不同的字符串里,所以分離的時候要保留這些字符串的完整性。

  2. 字符串分離成小字符串,然后用+號拼接起來,不過要注意操作符優(yōu)先級的問題,所以所有分離后的字符串,都要用括號包起來,讓這個+號的優(yōu)先級永遠(yuǎn)***。
    具體算法見 keep-line.js 中的 splitDoubleQuot (分離雙引號字符串)。

至此,整個應(yīng)用就完成了,可以順利完成從任意js和圖像生成圖形代碼了。

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI