簡體   English   中英

element.focus() 不適用於重新渲染的 contentEditable div 元素

[英]element.focus() doesn't work on rerendered contentEditable div element

編輯 little-platform-3291w

import React, { useEffect, useState } from "react";

import "./styles.css";

const RichText = () => {
  const [value, setValue] = useState("");

  useEffect(() => {
    const div = document.getElementById("textarea");

    if (div) {
      setTimeout(() => {
        div.focus();
      }, 0);
    }
  });

  return (
    <div
      className="rich-text"
      onInput={(e) => {
        setValue(e.target.innerText);
      }}
      contentEditable
      id="textarea"
      dangerouslySetInnerHTML={{
        __html: value
      }}
    />
  );
};

export default RichText;

我想實現富文本組件,想法是您可以在某個字段內輸入文本,您可以設置該文本的樣式(使其變為粗體、斜體、下划線等)。 我想在value state 變量上使用相同的文本值,然后以某種方式將其包裝在 html 標簽<p>Hello <b> Andrew</b></p>內,並在同一字段中實時顯示,樣式. 為了在divcontentEditable字段中顯示html標簽,我需要使用dangerouslySetInnerHTML ,這是主要問題。 每次按下按鈕時,我都會更新值,然后重新渲染組件,焦點位於字段的開頭,但我希望它在您輸入新文本時位於末尾。 我試圖通過ref => ref.current.focus()來實現它,它不起作用,在上面的代碼中你可以看到我也嘗試通過 vanilla js 使用超時來實現它,它也沒有work, autoFocus - 只能用於input, textarea, etc ,div 可以與此屬性一起使用。 我已將其保存到ref ,但隨后我無法在div內顯示包裝的 html 。 嘗試了很多案例,但它似乎是。 任何想法如何制作它?

問題是當使用useState鈎子與contentEditabledangerouslySetInnerHTML來同步值時。 當您在 div 中鍵入某些內容時,它會再次重新呈現並將 cursor 重新啟動。

您可以使用useRef組件中的實例變量(使用引用更新值)來解決此問題。

您應該使用innerHTML而不是innerText來保存 HTML 字符串

嘗試如下

import React, { useRef } from "react";

import "./styles.css";

const RichText = () => {
  const editableRef = useRef(null);
  const { current: value } = useRef(
    '<div style="color:green">my initial content</div>'
  );

  const setValue = (e) => {
    value.current = e.target.innerHTML;
  };

  const keepFocus = () => {
    const { current } = editableRef;
    if (current) {
      current.focus();
    }
  };

  return (
    <div
      className="rich-text"
      onInput={setValue}
      contentEditable
      id="textarea"
      ref={editableRef}
      onBlur={keepFocus}
      dangerouslySetInnerHTML={{
        __html: value
      }}
    />
  );
};

export default RichText;

代碼沙箱

import React from "react";

import "./styles.css";

class TextInput extends React.Component {
  constructor(props) {
    super();
    this.state = { value: "" };
  }

  shouldComponentUpdate() {
    return true;
  }

  componentDidUpdate() {
    const el = document.getElementById("textarea");

    if (el) {
      console.log(el.selectionStart, el.selectionEnd);

      var range, selection;
      if (document.createRange) {
        //Firefox, Chrome, Opera, Safari, IE 9+
        range = document.createRange(); //Create a range (a range is a like the selection but invisible)
        range.selectNodeContents(el); //Select the entire contents of the element with the range
        range.collapse(false); //collapse the range to the end point. false means collapse to end rather than the start
        selection = window.getSelection(); //get the selection object (allows you to change selection)
        selection.removeAllRanges(); //remove any selections already made
        selection.addRange(range); //make the range you have just created the visible selection
      } else if (document.selection) {
        //IE 8 and lower
        range = document.body.createTextRange(); //Create a range (a range is a like the selection but invisible)
        range.moveToElementText(el); //Select the entire contents of the element with the range
        range.collapse(false); //collapse the range to the end point. false means collapse to end rather than the start
        range.select(); //Select the range (make it the visible selection
      }
    }
  }

  update(value) {
    this.setState({ value });
  }

  render() {
    console.log(this.state.value);
    return (
      <div
        className="rich-text"
        onInput={(e) => {
          this.update(e.target.innerText);
        }}
        contentEditable
        id="textarea"
        dangerouslySetInnerHTML={{
          __html: `<b>${this.state.value}</b>`
        }}
      />
    );
  }
}

export default TextInput;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM