日韩欧美人妻无码精品白浆,www.大香蕉久久网,狠狠的日狠狠的操,日本好好热在线观看

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開(kāi)發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

自制體積不到 2kB 的代碼編輯器,areaEditor.js,增強(qiáng) textarea 標(biāo)簽的代碼編輯體驗(yàn)

freeflydom
2025年6月5日 9:35 本文熱度 515

https://github.com/kohunglee/areaEditor?

areaEditor.js 演示 : 

https://www.ccgxk.com/areaEditor.html

快速使用

只需這樣即可:


<script src="https://cdn.jsdelivr.net/gh/kohunglee/areaeditor/src/areaeditor.2.0.x.min.js" integrity="sha256-sP3tIYbNNHejSjhs3X0SBLULz54YEbR3g1dSJMvpCME=" crossorigin="anonymous"></script>

<script>

   var editor = new AreaEditor('textarea', {indentType : { type: 'space', count: 4 }});

</script>

這樣,您的網(wǎng)頁(yè)上所有的 <textarea> 就都可以縮進(jìn)了。當(dāng)然,{indentType : { type: 'space', count: 4 }} 是控制縮進(jìn)的類(lèi)型,space 是空格縮進(jìn),目前是 4 個(gè)空格。如果寫(xiě)成 {indentType : { type: 'tab', count: 1 }},則是一個(gè) '\t' TAB 制表符。

(不寫(xiě)這個(gè)配置,直接 new AreaEditor('textarea') 也可以,默認(rèn)是 4 個(gè)空格 )

后續(xù)也可以動(dòng)態(tài)進(jìn)行更改。比如:


editor.indentType.type = 'tab';  // 這樣可以動(dòng)態(tài)修改縮進(jìn)

當(dāng)然,如果是特定元素,也可以使用選擇器:


var editor = new AreaEditor('textarea');  // 選中所有的 textarea 元素

var editor = new AreaEditor('.code-editor');  // 選中所有 class 為 code-editor 的 textarea 元素

var editor = new AreaEditor('#code-editor');  // 選中 id 為 code-editor 的 textarea 元素

縮進(jìn)功能

最開(kāi)始,我找了很多資料,發(fā)現(xiàn)貌似沒(méi)人有針對(duì) <textarea> 的直接優(yōu)化。代碼編輯器是很多,大部分都是另辟一大堆 <div> 模擬新編輯框了,或者直接在大輪子 Code Mirror 基礎(chǔ)上進(jìn)一步改進(jìn)。

其實(shí),有時(shí)我們需要的并不多。比如,這些代碼編輯器有高亮的功能,能五顏六色顯示關(guān)鍵詞,其實(shí)這個(gè)屬于「消費(fèi)升級(jí)」的非剛需功能了,真正在編輯時(shí)的剛需是 代碼縮進(jìn)!


代碼縮進(jìn) > 自動(dòng)縮進(jìn) >> 高亮提示 > 智能補(bǔ)全 > 括號(hào)補(bǔ)全  > 糾錯(cuò)提示 > 語(yǔ)法高亮

我們肯定很討厭在 <textarea> 寫(xiě)代碼時(shí),一按 TAB 鍵,然后光標(biāo)跑外星的那種感覺(jué)。其實(shí)我們完全可以使用 js 來(lái)改良這個(gè)。

(可以試試在 https://www.ccgxk.com/cellhtmleditor.html 這個(gè)實(shí)時(shí)編輯頁(yè)面進(jìn)行調(diào)試下面的這些代碼 ~)


<textarea id="editor" placeholder="演示 tab 鍵縮進(jìn)"></textarea>

<script>

   editor.addEventListener('keydown', function(e){

       var start = e.target.selectionStart;  // 光標(biāo)開(kāi)始的位置

       var end = e.target.selectionEnd;  // 光標(biāo)結(jié)束的位置

       var value = e.target.value;  // 編輯器里的內(nèi)容



       if (e.key === 'Tab') {  // 按下 TAB 鍵

           e.preventDefault();  // 阻止默認(rèn)事件

           e.target.value = value.substring(0, start) + '\t' + value.substring(end);  // 添加 tab 字符

           e.target.selectionStart = e.target.selectionEnd = start + 1;  // 光標(biāo)向前 +1

       }

   });

</script>

首先,我們阻止了 tab 的默認(rèn)事件(跳到下一個(gè)表單元素)e.preventDefault();,然后我們調(diào)用 textarea 元素的 .value api 重新為其填充內(nèi)容。

然后是 e.target.selectionStart = e.target.selectionEnd = ... 讓我們的光標(biāo)位置放到應(yīng)該到達(dá)的地方。

.selectionStart 、 .selectionEnd 、 .value 這三個(gè) API 現(xiàn)在實(shí)現(xiàn)這樣一個(gè)小功能,然后還是這三個(gè) API ,漸漸貫徹了整個(gè)代碼。一切從這里開(kāi)始。

縮進(jìn)類(lèi)型

目前,縮進(jìn)格式并不統(tǒng)一,主流的縮進(jìn)是 4 個(gè)空格,所以,就得需要能切換。

(可以試試在 https://www.ccgxk.com/cellhtmleditor.html 這個(gè)實(shí)時(shí)編輯頁(yè)面進(jìn)行調(diào)試下面的這些代碼 ~)


<textarea id="editor" placeholder="演示縮進(jìn)類(lèi)型"></textarea>

<script>

   editor.addEventListener('keydown', function(e){

       var type = 'space';  // 縮進(jìn)類(lèi)型

       var indentCount = 4;  // 縮進(jìn)的字符數(shù)量

       var tabChar = (type === 'tab') ? '\t' : Array(indentCount + 1).join(' ');  // 縮進(jìn)字符



       var start = e.target.selectionStart;  // 光標(biāo)開(kāi)始的位置

       var end = e.target.selectionEnd;  // 光標(biāo)結(jié)束的位置

       var value = e.target.value;  // 編輯器里的內(nèi)容



       if (e.key === 'Tab') {  // 按下 TAB 鍵

           e.preventDefault();  // 阻止默認(rèn)事件

           e.target.value = value.substring(0, start) + tabChar + value.substring(end);  // 添加 tab 字符

           e.target.selectionStart = e.target.selectionEnd = start + indentCount;  // 光標(biāo)向前 +1

       }

   });

</script>

代碼里 Array(indentCount + 1).join(' ') 是一種技巧,可以返回 n 個(gè)空格,比如 Array(5 + 1).join(' ') 就是 5 個(gè)空格,Array(3 + 1).join(' ') 就等于 3 個(gè)空格。

根據(jù)這個(gè)原理,代碼的收縮也實(shí)現(xiàn)了。不過(guò),還是有很多坑,習(xí)慣上的坑:

  • 收縮后,光標(biāo)的選擇怎么計(jì)算?

  • 如果光標(biāo)的 start 位于縮進(jìn),比如空格上,又該怎么計(jì)算??

  • ...

增加縮進(jìn)很簡(jiǎn)單,減少縮進(jìn)沒(méi)想到這么復(fù)雜,計(jì)算邏輯還挺抽象,花了好幾個(gè)小時(shí)潤(rùn)色,才算完美解決,下面是最終的代碼:


// TAB 鍵盤(pán)的處理

if (e.key === 'Tab') {

e.preventDefault();

if (start === end) {  // 光標(biāo)未選中多個(gè)字符

e.target.value = value.substring(0, start) + this.tabChar + value.substring(end);

e.target.selectionStart = e.target.selectionEnd = start + this.tabLength;

return;

} else {

var contentArr = value.split('\n');

var contentArrOriginal = value.split('\n');

var startLine = (value.substring(0, start).match(/\n/g) || []).length;

var endLine = (value.substring(0, end).match(/\n/g) || []).length;

if (event.shiftKey) {  // 按下 Shift 鍵(減少縮進(jìn))。

for (var _i = startLine; _i <= endLine; _i++) {

contentArr[_i] = this._removeLeadingSpaces(contentArr[_i], this.tabLength);

}

e.target.value = contentArr.join('\n');

var lengthDiff = contentArrOriginal[startLine].length -

contentArrOriginal[startLine].trimStart().length; // 計(jì)算光標(biāo)起始點(diǎn)位于那一行

var moveLength = Math.min(this.tabLength, lengthDiff);



// 計(jì)算最小可縮進(jìn)值,以防止起始位置(如行5)縮進(jìn)至行4。

var limitLineNum = this._arrSum(contentArr, startLine);



// 處理選區(qū)起始在縮進(jìn)(空白)處的情況。

var startPoint = limitLineNum > start - moveLength - startLine ? limitLineNum + startLine : start - moveLength;



e.target.selectionStart = lengthDiff > 0 ? startPoint : start;

e.target.selectionEnd = end - (contentArrOriginal.join('\n').length - e.target.value.length);

} else {  // 單獨(dú)按 Tab 鍵(增加縮進(jìn)),這個(gè)簡(jiǎn)單,文章上面已經(jīng)寫(xiě)了

for (var _i = startLine; _i <= endLine; _i++) {

contentArr[_i] = this.tabChar + contentArr[_i];

}

e.target.value = contentArr.join('\n');

e.target.selectionStart = start + this.tabLength;

e.target.selectionEnd = end + this.tabLength * (startLine === endLine ? 1 : endLine - startLine + 1);

}

}

}

自動(dòng)補(bǔ)全括號(hào)

但,只有這種縮進(jìn),肯定還不夠,我們還需要那種寫(xiě)下括號(hào)后,再回車(chē),產(chǎn)生的那種自動(dòng)換行和縮進(jìn)的效果。

按下回車(chē):

順便把自動(dòng)括號(hào)也實(shí)現(xiàn)。

于是哐哐一頓實(shí)現(xiàn),計(jì)算還簡(jiǎn)單,但逐漸發(fā)現(xiàn)一個(gè)問(wèn)題。

這是程序 1.0 時(shí)候的一個(gè)案例:


<textarea placeholder="演示 enter 鍵 bug"></textarea>

<script src="https://cdn.jsdelivr.net/gh/kohunglee/areaeditor/src/areaeditor.1.0.x.min.js"></script>

<script>

   var editor = new AreaEditor('textarea');

</script>

當(dāng)我們用中文輸入法輸入時(shí),一回車(chē)(按照習(xí)慣,應(yīng)該只會(huì)輸入 jtxql 這六個(gè)字符),會(huì)產(chǎn)生這樣的效果:

顯然使用 addEventListener('keydown', ... ) 是不行的。

于是又加入了 addEventListener('input', ... ) 。keydown 和 input 是不一樣的。前者是在鍵盤(pán)按下的一瞬間觸發(fā),在字符輸入前(也因此可以阻止字符輸入),而后者 input 是在字符輸入后探測(cè)你按下了哪個(gè)按鍵。

犯難

這就犯了難,我到底是使用哪個(gè)來(lái)監(jiān)測(cè) enter 鍵的按下。如果是前者,那我避免不了這個(gè) bug,如果是后者,那畫(huà)面會(huì)跳動(dòng)一下,很詭異。

最后我還是使用后者,只不過(guò)我不是監(jiān)測(cè)的按鈕,而是字符 if(lastChar === '\n'){ ... },然后重新生成縮進(jìn)內(nèi)容,里面多來(lái)一個(gè)換行符即可。

自動(dòng)補(bǔ)全

自動(dòng)補(bǔ)全倒是沒(méi)有什么好說(shuō)的。唯一要說(shuō)的,【若用戶(hù)仍選擇手動(dòng)完成,則忽略】這個(gè)功能,讓這個(gè)自動(dòng)補(bǔ)全變得非常流暢。但我沒(méi)想到,要判斷用戶(hù)有沒(méi)有手動(dòng)補(bǔ)全,竟然要判斷三個(gè)布爾:前一個(gè)字符,是否屬于要補(bǔ)全的符號(hào),后一個(gè)字符是否等于應(yīng)補(bǔ)全的符號(hào),用戶(hù)輸入的是否等于已經(jīng)補(bǔ)全的符號(hào)。


var autoPairs = {

'{': '}',

'[': ']',

'(': ')',

'"': '"',

"'": "'",

'`': '`',

};

if (['{', '(', '[', '"', "'", '`', ']', '}', ')'].includes(lastChar) && start === end) {

if(this.isPreventAuto){

this.isPreventAuto = false;

return;

}

var pairChar = autoPairs[lastChar]  || '';

for (var leftBrace in autoPairs) {



// 若用戶(hù)仍選擇手動(dòng)完成,則忽略

if (leftBrace === secondLastChar && autoPairs[leftBrace] === lastChar && nextChar === lastChar) {

e.target.value = value.substring(0, start) + value.substring(start + 1);

e.target.selectionStart = e.target.selectionEnd = start;

return;

}

}

e.target.value = value.substring(0, start) + pairChar + value.substring(start);

e.target.selectionStart = e.target.selectionEnd = start;

}

阻止補(bǔ)全

其實(shí),上面的這些行為,并不能一直都有效。所以我又設(shè)立了阻止補(bǔ)全。不能說(shuō)我們按快捷鍵復(fù)制粘貼的時(shí)候,也順手補(bǔ)全了,也不能說(shuō)我們?cè)诎磩h除鍵的時(shí)候也給補(bǔ)全了(o( ̄▽?zhuān)?d 這樣就陷入死循環(huán)了 ~ 一個(gè)永遠(yuǎn)也刪不掉的右括號(hào))


AreaEditor.prototype.isPreventAuto = false;  // 是否阻止某些自動(dòng)腳本

檢測(cè)到一些按鍵 或 粘貼事件 addEventListener('paste', ...); 后,就不再執(zhí)行。

編輯框抖動(dòng)

一個(gè)不知起源于何時(shí)的 textarea 特性,當(dāng)行數(shù)比較大時(shí),回車(chē)會(huì)讓輸入框抖一下,十分影響..... 起碼影響心情:

(可以試試在 https://www.ccgxk.com/cellhtmleditor.html 這個(gè)實(shí)時(shí)編輯頁(yè)面進(jìn)行調(diào)試下面的這些代碼 ~)


<textarea id=demoEditor rows=10 placeholder="演示編輯框抖動(dòng)"></textarea>

<script src="https://cdn.jsdelivr.net/gh/kohunglee/areaeditor/src/areaeditor.1.0.js"></script>

<script>

   var content = '';

   for(var i = 0; i < 200; i++){

       content += i+'\n'

   }

   demoEditor.value = content;

</script>

于是

這是瀏覽器的原生特性(bug),意義不明。

當(dāng)然,這個(gè)問(wèn)題好解決,只需要記錄下高度,在完成我們的操作后將高度還原即可。

在空行按下刪除鍵,清空

在一個(gè)只存在縮進(jìn)、空格的行,我們按下刪除鍵,不出意外,目的只有一個(gè),就是將這行刪干凈。所以,我又加上這樣一個(gè)功能,在空行按下刪除鍵,清空。

本以為只是一兩行代碼才能完成,最后搞了一坨:


if (e.key === 'Backspace') {

var contentArr = value.split('\n');

var startLine = (value.substring(0, start).match(/\n/g) || []).length;



// 當(dāng)前行僅包含空格和制表符

if(start === end && (/^[\s\t]*$/.test(contentArr[startLine]) && contentArr[startLine] !== '')){

e.target.selectionStart = this._arrSum(contentArr, startLine) + startLine;

e.target.selectionEnd = start;

}

}

體驗(yàn)感大大的好。

封裝代碼

我想把它做成一個(gè)第三方的引用庫(kù),那么我就要盡可能寫(xiě)的標(biāo)準(zhǔn)一點(diǎn)。

模仿 jQuery、Zepto 將它封裝了一下。

首先是 UMD 模塊化,


(function (global, factory) {

   if (typeof define === 'function' && define.amd) {  // UMD 模式

       define([], factory);  // AMD

   } else if (typeof module === 'object' && module.exports) {

       module.exports = factory();  // CommonJS

   } else {

       global.AreaEditor = factory();  // 這樣寫(xiě),可以不用 new 關(guān)鍵字來(lái)調(diào)用

   }

}(this, function () {

   'use strict';



// 構(gòu)造函數(shù)

function AreaEditor(element, options = {indentType : { type: 'space', count: 4 }}) {



.....



.....



return AreaEditor;

}));

第一個(gè),是依照過(guò)去我們常用的 requireJS 要求的格式來(lái)定義的,這是一個(gè)模塊化工具,讓我們的 JS 文件們可以按需加載。雖然在 ES6 時(shí)代日薄西山,但還是能用得到。學(xué)習(xí)這個(gè)可以看阮一峰大佬的這篇文章

第二個(gè)是 CommonJS 環(huán)境使用的,也就是服務(wù)器端。主要用于 node.js 。可以供 require('./logger.js') 這種語(yǔ)法使用。

第三個(gè)就是我們現(xiàn)在使用的這種方式,即瀏覽器直接調(diào)用。

里面的 factory() 是工廠函數(shù), 'use strict'; 及以下就是這個(gè)函數(shù)的內(nèi)容。我們只需將我們的 AreaEditor 函數(shù)寫(xiě)入即可。

AreaEditor() 是構(gòu)造函數(shù),通常使用大寫(xiě)字母開(kāi)頭。就好像一個(gè)對(duì)象一樣,不過(guò)調(diào)用的時(shí)候需要寫(xiě) new ,有了上面的 factory() 的處理后,不寫(xiě) new 關(guān)鍵字也可以。


怎么壓縮 JavaScript 代碼

初步壓縮,主流的有三個(gè)選擇:

第一個(gè)是谷歌公司使用 Java 搞的智能壓縮,可以分析代碼把冗余給鏟除,確保結(jié)果不變。不過(guò)效果和下面兩個(gè)差不多。

第三個(gè) Terser 我們可能都間接用過(guò),它是 webpack 這個(gè)打包工具的默認(rèn)壓縮工具。其實(shí)它是在 UglifyJS 基礎(chǔ)上迭代的。

在這里,我使用了 UglifyJS 。它也會(huì)智能將代碼里的多余的地方優(yōu)化,以實(shí)現(xiàn)盡可能小的體積:


var a=1;var a=2;

// 合并重復(fù)變量

var a=2



alert('a' + 'b');

// 優(yōu)化

alert("ab");



function a(){

   var info = 'a' + 'b';

   alert(info);

}

// 優(yōu)化

function a(){alert("ab")}

它本身是一個(gè) node.js 庫(kù),無(wú)法直接在瀏覽器上運(yùn)行,不過(guò)有大佬將其轉(zhuǎn)化為了瀏覽器端。我又將其配置表和界面給翻譯成中文,就是下面這個(gè)地址:

https://git.ccgxk.com/jscompression/jsminifier.html

使用它生成后的代碼,還沒(méi)有到 2kb 這個(gè)階段,然后我又找到了個(gè)利用字母出現(xiàn)頻次,構(gòu)成字典,然后進(jìn)行壓縮的 js 壓縮工具。

常出現(xiàn)在一些 代碼高爾夫 炫技比賽里,比比誰(shuí)能用更小的體積實(shí)現(xiàn)更復(fù)雜的功能或游戲這種比賽里,類(lèi)似于 https://js13kgames.com/ 。

我把那個(gè)界面搞的漂亮了一點(diǎn),然后將全局變量改了一下名,就是這個(gè)頁(yè)面:

https://git.ccgxk.com/jscompression/jscrush.html

這樣就差不多 2kb 了。

轉(zhuǎn)自https://www.cnblogs.com/duyuanshang/p/18856762


該文章在 2025/6/5 9:40:49 編輯過(guò)
關(guān)鍵字查詢(xún)
相關(guān)文章
正在查詢(xún)...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專(zhuān)業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車(chē)隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開(kāi)發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類(lèi)企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷(xiāo)售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶(hù)的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

亚洲素人精品人妻99| 亚洲 欧美 日韩 国产 一区二区| av综合图区| 亚洲综合欧美在线一区在线播放| www.超碰日韩| 老年人黄色影院| 国产大鸡巴大鸡巴小骚逼逼小骚逼逼| 98无码人妻精品一区二区三区 | 色综合久久五月| 中文在线一区综合| 无码久久 中文字幕| 不卡成人AV在线| 亚洲欧美日韩色欲| 欧美男人肛交无码视频| 一插二进三入视频| 插久久久久久| 国产一级射精大片| 欧美久久黄色| 欧美日韩一区二区三区四区巨吊操屄| αv天堂8| www.一区91av| 嫩草鲁丝久久精品熟女| 成人乱码在线视频| 欧美一区二区三放荡人妇| 日韩三级动作一区二区| 日本国产伦理片精品| 亚洲天堂a人v| 一飞二区精品| 一二区三区网站| 亚洲日欧美一区二区| 亚洲欧洲AV免费在线| 午夜网| 美女网站蜜桃一区二区| 日韩不卡一区精品| www.亚洲老熟妇| 日韩美女电影第三页| 夜色婷婷少妇| 亚洲aⅴ无码精品狠狠爱| 欧美、日韩、国产一区二区| 亚洲成色www噜噜噜| 欧美日韩精品第二区在线|