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狀態變數中使用相同的文本值,然后以某種方式將其包裝在 html 標記<p>Hello <b> Andrew</b></p>中,并在同一個欄位中實時顯示,樣式化。為了在,欄位中顯示html標簽,我需要使用,這是主要問題。每次按下按鈕時,我都會更新值,然后重新渲染組件,焦點位于欄位的開頭,但我希望它在您輸入新文本時結束。我試圖通過=>來實作它,但它不起作用,在上面的代碼中你可以看到我也嘗試通過 vanilla js 使用 timeout 來實作它,它也不起作用,divcontentEditabledangerouslySetInnerHTMLrefref.current.focus()autoFocus- 只能用于input, textarea, etc,div 可以與此屬性一起使用。我已經將它保存到ref,但是我無法在div. 嘗試了很多案例,但似乎都是。任何想法如何制作它?
uj5u.com熱心網友回復:
問題是當使用useState鉤子contentEditable和dangerouslySetInnerHTML同步值時。當您在 div 中鍵入內容時,它會再次重新呈現并將游標帶回起點。
您可以在函陣列件中使用實體變數(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;
代碼沙箱
uj5u.com熱心網友回復:
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;
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/411665.html
標籤:
