Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/451.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React组件:使用危险的插入符号位置编辑内容的div_Javascript_Reactjs_React Hooks - Fatal编程技术网

Javascript React组件:使用危险的插入符号位置编辑内容的div

Javascript React组件:使用危险的插入符号位置编辑内容的div,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我目前正在使用React构建一个具有contenteditable div的组件。由于内容是由用户生成的,因此我试图通过使用危险的HTML使我的组件状态与其内容保持同步。我的另一个选择是直接更新innerHTML属性 根据对另一个SO问题的以下回答,我认为使用危险的SetinenerHTML是很重要的: 是的,有区别 使用innerHTML和危险的LysetinerHTML的直接效果是相同的——DOM节点将使用注入的HTML进行更新 然而,在幕后,当您使用危险的LySetinerHTML时,它

我目前正在使用React构建一个具有
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>
  );
}