一個小的反應鉤將元素變成完全可渲染且可編輯的內容表面,例如代碼編輯器,使用可滿足的(和魔術)
useEditable是一個小鉤子,使元素仍然contenteditable ,同時仍然完全呈現。這是僅在2kB中創建小型代碼編輯器或散文Textareas的理想選擇!
它的目的是允許任何元素可以編輯,同時仍然能夠對其進行正常的反應元素 - 沒有innerHTML ,並且必須處理與RAW HTML的操作或渲染,或者從Scratch啟動完整的編輯器項目。
使用prism-react-renderer在Codesandbox上查看完整的演示!
與react一起首先安裝use-editable :
yarn add use-editable
# or
npm install --save use-editable然後,您將能夠導入useEditable ,並將其傳遞給HTMLElement REF和一個onChange處理程序。
import React , { useState , useRef } from 'react' ;
import { useEditable } from 'use-editable' ;
const RainbowCode = ( ) => {
const [ code , setCode ] = useState ( 'function test() {}nconsole.log("hello");' ) ;
const editorRef = useRef ( null ) ;
useEditable ( editorRef , setCode ) ;
return (
< div className = "App" >
< pre
style = { { whiteSpace : 'pre-wrap' , fontFamily : 'monospace' } }
ref = { editorRef }
>
{ code . split ( / r?n / ) . map ( ( content , i , arr ) => (
< React . Fragment key = { i } >
< span style = { { color : `hsl( ${ ( ( i % 20 ) * 17 ) | 0 } , 80%, 50%)` } } >
{ content }
</ span >
{ i < arr . length - 1 ? 'n' : null }
</ React . Fragment >
) ) }
</ pre >
</ div >
) ;
} ;就像那樣,我們已經將editorRef的useEditable連接起來,它指向正在渲染的<pre>元素,並指向啟動包含一些代碼狀態的setCode 。
該庫已對其進行測試,應適當使用:
IE 11中存在已知問題,因為MutationObserver方法無法讀取已通過contenteditable刪除的文本節點。
傳統上,選擇React中的編輯表面時,有三個選擇。一個人可以選擇一個大型項目,例如Prosemirror / codemirror,或者可以控制大部分編輯和渲染事件,因此具有相當有意義的觀點,或者有可能僅使用contenteditable和渲染的HTML來替換在元素的內容中,或者最後一個可以將textarea銷售的內容與重疊的div組合在一起,以使其與內容結合使用。
所有三個選項都不允許對實際渲染的內容進行太多自定義,或者對渲染和管理可編輯內容的容易性有多大限制。
那麼,是什麼使渲染如此難以contenteditable元素呢?
通常,這很艱難,因為它們直接編輯DOM。這會導致大多數渲染的庫,例如React和Preatct混淆,因為它們的基本虛擬DOMS與實際的DOM結構不再匹配。為了防止此問題use-editable可以創建一個MutationObserver ,該突變處理器觀察對contenteditable元素所做的所有更改。在報告這些更改之前,首先對其進行反應,將所有更改倒回DOM,以便React可以看到它的期望。
此外,它還保留了Caret,選擇的當前位置,並恢復它一旦React更新了DOM本身。對於contenteditable編輯器而言,這是一種相當常見的技術,但是MutationObserver添加是使use-editable可讓另一個視圖庫更新元素內容的方法。
當前,渲染元素的文本內容必須最終與代碼輸入完全匹配,或者您的實現必須能夠將渲染的文本內容轉換回您使用的狀態。這是對contenteditable工作的限制,因為它們只會捕獲實際的DOM內容。由於use-editable並不是要成為管理渲染週期的完整組件,因此它不必保留任何額外的狀態,而只會將DOM的文本傳遞回onChange回調。
使用onChange回調,您還會收到一個Position對象,描述了光標位置,當前行號以及線的內容,直到光標為自動搜索器很有用,這對自動搜索很有用,然後可以將其應用於update useEditable的返回以更新光標位置的更新功能。
第一個參數是elementRef ,並接受類型RefObject<HTMLElement>的Ref對象,該對象指向應該變得可編輯的元素。在鉤子的運行時,該裁判被允許為null或更改。只要裁判的更改是由React觸發的,一切都應該按照預期的方式行事。
第二個參數是onChange ,並接受類型的回調(text: string, pos: Position) => void ,每當contenteditable內容的內容更改時都稱為void。需要設置此設置,以便它觸發元素內容的啟用。
onChange接收的text只是元素內容的文本表示,而其接收到的Position包含光標的當前位置,行號(零索引)以及當前陣容的內容,直到光標為AutoSuggestions有用。
第三個參數是可選的options對象。這目前接受了兩個選擇掛鉤的編輯行為的選項:
disabled選項通過再次從中刪除可滿足contentEditable屬性來禁用編輯。indentation選項可以是許多顯示的凹痕空間。這也可以實現改進的Tab鍵行為,該行為將縮小當前線路或持有當前線的限制(請注意,這將使編輯器作為焦點陷阱行為!)設置options.indentation時,然後useEditable將防止插入標籤字符,而是將插入指定數量的Whitespaces,這使得對列的處理變得更加容易。
此外, useEditable掛鉤還返回帶有幾種方法的Edit句柄,如下所示。
Edit.update(content: string): void
在調整Caret位置的同時,替換了可編輯的全部內容。這將通過當前內容和傳遞內容之間的長度差異移動。
Edit.insert(append: string, offset?: number): void
在偏移範圍內刪除文本(接受負偏移)的同時,將新文本插入。例如,當將offset設置為-1時,將單個字符在插入任何新文本之前將單個字符刪除。將其設置為2 ,然後將兩個字符右側的兩個字符刪除。 append文本也可以設置為空字符串,僅在不插入任何文本的情況下應用刪除。當選擇任何文本時,首先將其簡單地刪除,並且offset被忽略。
Edit.move(pos: number | { row: number; column: number }): void
這將袋移到指定位置。該位置可以是字符索引( number ),也可以是分別指定row和column坐標。
Edit.getState(): { text: string; position: Position }
此方法允許獲得可編輯的當前狀態,這與onChange通常收到的狀態相同。當選擇可編輯時,在鍵入處理程序中添加自定義編輯操作或編程模仿onChange時,這很有用。
react-live是早期contenteditable編輯之一。 (但是使用RAW HTML更新)react-simple-code-editor是第一個使用拆分文本方面和渲染表面實現的(?)庫,它提出了一個不錯的編輯API的外觀。codejar包含了管理選擇的最佳技巧,儘管它缺乏一些Firefox解決方案。它還使用RAW HTML突出顯示 /更新。codemirror.next是在處理文本輸入和DOM更新技巧時查看不同技術的寶貴來源。 穩定:強大的不打算為該項目開發任何新功能。我們仍在回應錯誤報告和安全問題。我們仍然歡迎該項目的PR,但是包含新功能的PR應該很小且易於集成,並且不應包括破壞更改。