Javascript React组件:使用危险的插入符号位置编辑内容的div
我目前正在使用React构建一个具有Javascript React组件:使用危险的插入符号位置编辑内容的div,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我目前正在使用React构建一个具有contenteditable div的组件。由于内容是由用户生成的,因此我试图通过使用危险的HTML使我的组件状态与其内容保持同步。我的另一个选择是直接更新innerHTML属性 根据对另一个SO问题的以下回答,我认为使用危险的SetinenerHTML是很重要的: 是的,有区别 使用innerHTML和危险的LysetinerHTML的直接效果是相同的——DOM节点将使用注入的HTML进行更新 然而,在幕后,当您使用危险的LySetinerHTML时,它
contenteditable div
的组件。由于内容是由用户生成的,因此我试图通过使用危险的HTML
使我的组件状态
与其内容保持同步。我的另一个选择是直接更新innerHTML
属性
根据对另一个SO问题的以下回答,我认为使用危险的SetinenerHTML
是很重要的:
是的,有区别
使用innerHTML和危险的LysetinerHTML的直接效果是相同的——DOM节点将使用注入的HTML进行更新
然而,在幕后,当您使用危险的LySetinerHTML时,它会让React知道该组件内部的HTML不是它关心的东西
因为React使用虚拟DOM,所以当它将diff与实际DOM进行比较时,它可以直接绕过检查该节点的子节点,因为它知道HTML来自另一个源。因此,性能有所提高
更重要的是,如果您只是使用innerHTML,React无法知道DOM节点已被修改。下次调用渲染函数时,React将覆盖手动注入的内容,它认为DOM节点的正确状态应该是什么
但现在我想到了以下问题:
当有一个新的输入,并且您使用新的Html设置状态时,您的组件将使用新的DangerlySetinerHTML={{{{uuuuHTML:Html}}
重新呈现,并且插入符号跳转位置(返回到目前为止测试的所有浏览器上的行的开头:Chrome、Firefox、Edge)
但这里没有什么新鲜事。如果我使用innerHTML
设置新的html,也会发生这种情况(插入符号跳转)。使用新的html
接收state
的问题在于,当您设置新的状态时,它是对setState()
的异步调用
因此,您不能立即调用placeCaret()
。只有使用setTimeout()
为新的状态
留出一段时间来更新组件时,它才起作用
setHTML(root.innerHTML);
setTimeout(() => placeCaret(root.innerText.length), 100); // TIMEOUT NEEDED
//placeCaret(root.innerText.length);
无论如何,这是一个解决办法,但最终会导致糟糕的用户体验,因为用户可以看到插入符号在每个按键上跳跃
问题
对于这种插入符号跳转的情况,是否有一种使用危险的SytenerySetinerHTML
的解决方案?或者我应该避免使用它,直接操作innerHTML
,这样我就可以立即对元素进行更改吗
注意:我不认为使用阻止组件更新应该是一个可行的解决方案。因为有时候我实际上需要修改html,比如,在跨距中添加一些文本,等等。所以我需要组件更新,而不需要插入符号
import React,{useRef,useState}来自“React”;
从“react dom”导入react dom;
从“样式化组件”导入样式化;
常数S={};
S.div=styled.div`
边框:1px点蓝色;
`;
函数App(){
const divRef=useRef(null);
const[html,setHTML]=useState(“
”);
函数onInput(){
const root=divRef.current;
setHTML(root.innerHTML);
setTimeout(()=>placeCaret(root.innerText.length),100);
//placeCaret(root.innerText.length);
}
//将插入符号放回原位
功能位置插入符号(位置){
const root=divRef.current;
const selection=window.getSelection();
const range=selection.getRangeAt(0);
range.setStart(root.firstChild.firstChild,位置);
}
函数onKeyDown(e){
console.log(“On keydown…”+e.key);
如果(e.key==“输入”){
e、 预防默认值();
}
}
返回(
);
}
我认为您应该去掉java标记,改为使用javascript标记。@lungu当然!谢谢它没有自动完成我的字符串。我的错。你好@cbdev420,你能解决这个问题吗?我们目前在您的一个项目中也有相同的项目。谢谢您的帮助。@natterstefan我最终采用的解决方案是使内容可编辑div不受控制(无状态)。因此,用户可以自由编辑。您仍然可以使用onInput
方法在useRef
变量中保留和更新div
的文本值,以便对其执行一些逻辑。注意:最后,我完全放弃了内容可编辑的div
s,因为不同浏览器之间没有关于文本的html
的标准。对于我想做的事情来说太混乱了。谢谢你的回答@cbdev420。这也是我的经历。我们也放弃了使用contentEditable
,现在开始使用。在我们当前的用例中,这已经足够了。谢谢
import React, { useRef, useState } from "react";
import ReactDOM from "react-dom";
import styled from "styled-components";
const S = {};
S.div = styled.div`
border: 1px dotted blue;
`;
function App() {
const divRef = useRef(null);
const [html, setHTML] = useState("<div><br></div>");
function onInput() {
const root = divRef.current;
setHTML(root.innerHTML);
setTimeout(() => placeCaret(root.innerText.length), 100);
//placeCaret(root.innerText.length);
}
// PLACE CARET BACK IN POSITION
function placeCaret(position) {
const root = divRef.current;
const selection = window.getSelection();
const range = selection.getRangeAt(0);
range.setStart(root.firstChild.firstChild, position);
}
function onKeyDown(e) {
console.log("On keydown... " + e.key);
if (e.key === "Enter") {
e.preventDefault();
}
}
return (
<React.Fragment>
<S.div
contentEditable
ref={divRef}
onInput={onInput}
onKeyDown={onKeyDown}
dangerouslySetInnerHTML={{ __html: html }}
/>
</React.Fragment>
);
}