91网首页-91网页版-91网在线观看-91网站免费观看-91网站永久视频-91网站在线播放

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

自制體積不到 2kB 的代碼編輯器,areaEditor.js,增強 textarea 標簽的代碼編輯體驗

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

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>

這樣,您的網頁上所有的 <textarea> 就都可以縮進了。當然,{indentType : { type: 'space', count: 4 }} 是控制縮進的類型,space 是空格縮進,目前是 4 個空格。如果寫成 {indentType : { type: 'tab', count: 1 }},則是一個 '\t' TAB 制表符。

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

后續也可以動態進行更改。比如:


editor.indentType.type = 'tab';  // 這樣可以動態修改縮進

當然,如果是特定元素,也可以使用選擇器:


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 元素

縮進功能

最開始,我找了很多資料,發現貌似沒人有針對 <textarea> 的直接優化。代碼編輯器是很多,大部分都是另辟一大堆 <div> 模擬新編輯框了,或者直接在大輪子 Code Mirror 基礎上進一步改進。

其實,有時我們需要的并不多。比如,這些代碼編輯器有高亮的功能,能五顏六色顯示關鍵詞,其實這個屬于「消費升級」的非剛需功能了,真正在編輯時的剛需是 代碼縮進


代碼縮進 > 自動縮進 >> 高亮提示 > 智能補全 > 括號補全  > 糾錯提示 > 語法高亮

我們肯定很討厭在 <textarea> 寫代碼時,一按 TAB 鍵,然后光標跑外星的那種感覺。其實我們完全可以使用 js 來改良這個。

(可以試試在 https://www.ccgxk.com/cellhtmleditor.html 這個實時編輯頁面進行調試下面的這些代碼 ~)


<textarea id="editor" placeholder="演示 tab 鍵縮進"></textarea>

<script>

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

       var start = e.target.selectionStart;  // 光標開始的位置

       var end = e.target.selectionEnd;  // 光標結束的位置

       var value = e.target.value;  // 編輯器里的內容



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

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

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

           e.target.selectionStart = e.target.selectionEnd = start + 1;  // 光標向前 +1

       }

   });

</script>

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

然后是 e.target.selectionStart = e.target.selectionEnd = ... 讓我們的光標位置放到應該到達的地方。

.selectionStart 、 .selectionEnd 、 .value 這三個 API 現在實現這樣一個小功能,然后還是這三個 API ,漸漸貫徹了整個代碼。一切從這里開始。

縮進類型

目前,縮進格式并不統一,主流的縮進是 4 個空格,所以,就得需要能切換。

(可以試試在 https://www.ccgxk.com/cellhtmleditor.html 這個實時編輯頁面進行調試下面的這些代碼 ~)


<textarea id="editor" placeholder="演示縮進類型"></textarea>

<script>

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

       var type = 'space';  // 縮進類型

       var indentCount = 4;  // 縮進的字符數量

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



       var start = e.target.selectionStart;  // 光標開始的位置

       var end = e.target.selectionEnd;  // 光標結束的位置

       var value = e.target.value;  // 編輯器里的內容



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

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

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

           e.target.selectionStart = e.target.selectionEnd = start + indentCount;  // 光標向前 +1

       }

   });

</script>

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

根據這個原理,代碼的收縮也實現了。不過,還是有很多坑,習慣上的坑:

  • 收縮后,光標的選擇怎么計算?

  • 如果光標的 start 位于縮進,比如空格上,又該怎么計算??

  • ...

增加縮進很簡單,減少縮進沒想到這么復雜,計算邏輯還挺抽象,花了好幾個小時潤色,才算完美解決,下面是最終的代碼:


// TAB 鍵盤的處理

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

e.preventDefault();

if (start === end) {  // 光標未選中多個字符

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 鍵(減少縮進)。

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; // 計算光標起始點位于那一行

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



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

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



// 處理選區起始在縮進(空白)處的情況。

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 {  // 單獨按 Tab 鍵(增加縮進),這個簡單,文章上面已經寫了

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);

}

}

}

自動補全括號

但,只有這種縮進,肯定還不夠,我們還需要那種寫下括號后,再回車,產生的那種自動換行和縮進的效果。

按下回車:

順便把自動括號也實現。

于是哐哐一頓實現,計算還簡單,但逐漸發現一個問題。

這是程序 1.0 時候的一個案例:


<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>

當我們用中文輸入法輸入時,一回車(按照習慣,應該只會輸入 jtxql 這六個字符),會產生這樣的效果:

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

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

犯難

這就犯了難,我到底是使用哪個來監測 enter 鍵的按下。如果是前者,那我避免不了這個 bug,如果是后者,那畫面會跳動一下,很詭異。

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

自動補全

自動補全倒是沒有什么好說的。唯一要說的,【若用戶仍選擇手動完成,則忽略】這個功能,讓這個自動補全變得非常流暢。但我沒想到,要判斷用戶有沒有手動補全,竟然要判斷三個布爾:前一個字符,是否屬于要補全的符號,后一個字符是否等于應補全的符號,用戶輸入的是否等于已經補全的符號。


var autoPairs = {

'{': '}',

'[': ']',

'(': ')',

'"': '"',

"'": "'",

'`': '`',

};

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

if(this.isPreventAuto){

this.isPreventAuto = false;

return;

}

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

for (var leftBrace in autoPairs) {



// 若用戶仍選擇手動完成,則忽略

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;

}

阻止補全

其實,上面的這些行為,并不能一直都有效。所以我又設立了阻止補全。不能說我們按快捷鍵復制粘貼的時候,也順手補全了,也不能說我們在按刪除鍵的時候也給補全了(o( ̄▽ ̄)d 這樣就陷入死循環了 ~ 一個永遠也刪不掉的右括號)


AreaEditor.prototype.isPreventAuto = false;  // 是否阻止某些自動腳本

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

編輯框抖動

一個不知起源于何時的 textarea 特性,當行數比較大時,回車會讓輸入框抖一下,十分影響..... 起碼影響心情:

(可以試試在 https://www.ccgxk.com/cellhtmleditor.html 這個實時編輯頁面進行調試下面的這些代碼 ~)


<textarea id=demoEditor rows=10 placeholder="演示編輯框抖動"></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),意義不明。

當然,這個問題好解決,只需要記錄下高度,在完成我們的操作后將高度還原即可。

在空行按下刪除鍵,清空

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

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


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

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

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



// 當前行僅包含空格和制表符

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

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

e.target.selectionEnd = start;

}

}

體驗感大大的好。

封裝代碼

我想把它做成一個第三方的引用庫,那么我就要盡可能寫的標準一點。

模仿 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();  // 這樣寫,可以不用 new 關鍵字來調用

   }

}(this, function () {

   'use strict';



// 構造函數

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



.....



.....



return AreaEditor;

}));

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

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

第三個就是我們現在使用的這種方式,即瀏覽器直接調用。

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

AreaEditor() 是構造函數,通常使用大寫字母開頭。就好像一個對象一樣,不過調用的時候需要寫 new ,有了上面的 factory() 的處理后,不寫 new 關鍵字也可以。


怎么壓縮 JavaScript 代碼

初步壓縮,主流的有三個選擇:

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

第三個 Terser 我們可能都間接用過,它是 webpack 這個打包工具的默認壓縮工具。其實它是在 UglifyJS 基礎上迭代的。

在這里,我使用了 UglifyJS 。它也會智能將代碼里的多余的地方優化,以實現盡可能小的體積:


var a=1;var a=2;

// 合并重復變量

var a=2



alert('a' + 'b');

// 優化

alert("ab");



function a(){

   var info = 'a' + 'b';

   alert(info);

}

// 優化

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

它本身是一個 node.js 庫,無法直接在瀏覽器上運行,不過有大佬將其轉化為了瀏覽器端。我又將其配置表和界面給翻譯成中文,就是下面這個地址:

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

使用它生成后的代碼,還沒有到 2kb 這個階段,然后我又找到了個利用字母出現頻次,構成字典,然后進行壓縮的 js 壓縮工具。

常出現在一些 代碼高爾夫 炫技比賽里,比比誰能用更小的體積實現更復雜的功能或游戲這種比賽里,類似于 https://js13kgames.com/ 。

我把那個界面搞的漂亮了一點,然后將全局變量改了一下名,就是這個頁面:

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

這樣就差不多 2kb 了。

轉自https://www.cnblogs.com/duyuanshang/p/18856762


該文章在 2025/6/5 9:40:49 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 欧美中文字幕在线视 | 果冻传媒网站入口 | 午夜亚洲理 | 国自产在线 | 韩国午夜插插 | 午夜偷拍精品福利 | 国产精品网址 | 国产天堂一区 | 成人午夜视频精品一 | 国产高清不卡一区 | 精品国自产拍视频 | 国产日韩欧美第二页 | 国产欧美日韩主播 | 亚洲无码在线免费 | 韩国女优 | 日本不卡一区二区 | 国产v视频 | 日韩欧美视频免费看 | 日本国产在线视频 | 国产美乳艺术一区 | 伦理电影网在线观看 | 国产偷p视频 | 欧洲高清视频在线 | 午夜理论片 | 欧美一级无片 | 日韩成人AⅤ | 91精品国产现 | 91福利在线视 | 91免费观看视频 | 欧美亚洲日韩国产网 | 老妇炕上偷老汉 | 日本一区二区在线 | 国产伦精品一区二区 | 亚洲无码1区 | 日韩精品a∨片蜜臀 | 区国产二区| 精品欧美不卡一区 | 国产人兽在线 | 99国产精品| 91自拍视频在线 | 国产高清视频一区 |