一个小的反应钩将元素变成完全可渲染且可编辑的内容表面,例如代码编辑器,使用可满足的(和魔术)
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应该很小且易于集成,并且不应包括破坏更改。