gpt4 book ai didi

javascript - react : How to maintain caret position when editing contentEditable div?

转载 作者:行者123 更新时间:2023-11-27 22:55:55 28 4
gpt4 key购买 nike

目前

  1. 我有一个 react 组件,当用户点击 contentEditable newValue 时存储 <div> ,并在用户键入时更新 newValue注意:我以这种方式设置此行为有两个主要原因:(1) 我不想在每次击键时发送要保存的数据,以及 (2) 我计划使用这个 div,其中检查每个输入以验证输入是否为数字。
  2. newValue失去焦点时发送<div>进行保存,然后重置prop的状态。

问题

onChangeHandler 将插入符号在可编辑的 div 中的位置移动到左侧。这导致击键 123456 显示为 654321

代码:

class Input extends Component {

constructor(props) {
super(props);
this.state = {
//newValue input by user
newValue : undefined
}
}

//handler during key press / input
onChangeHandler = event => {
let targetValue = event.currentTarget.textContent;
this.setState({"newValue": targetValue})
}

//handler when user opens input form
onBlurHandler = event => {
//some code that sends the "newValue" to be saved, and resets state
}

render() {
//determine which value to show in the div
let showValue;
//if there is a new value being input by user, show this value
if (this.state.newValue !== undefined) {
showValue = this.state.newValue;
} else {
//if prop has no value e.g. null or undefined, use "" placeholder
if (this.props.value) {
showValue = this.props.value;
} else {
showValue = "";
}
}

return (
<table>
<tbody>
<td>
<div
contentEditable="true"
suppressContentEditableWarning="true"
onInput={this.onChangeHandler.bind(this)}
onBlur={this.onBlurHandler}
>{showValue}
</div>
</td>
</tbody>
</table>
)
}
}

export default Input;

注意事项

  1. 我之前使用没有这个问题的 <textarea> 执行此操作,但切换到 <div> 以更好地控制自动调整 div 高度行为(ref CSS: Remove scroll bar and replace with variable height for textarea in a table <td>)
  2. 我已经能够找到许多相关的答案,但没有一个是特定于 react 的,例如Maintain cursor position in contenteditable div。我假设是因为 React 在每次笔划后重新加载组件,所以才会出现此问题。
  3. 我以前在输入上没有 ChangeHandler,这工作正常,但我无法记录每次按键并验证字符是否为数字。

最佳答案

我能够按照 https://stackoverflow.com/a/13950376/1730260 中的解决方案使此工作正常进行

主要变化:

  1. 添加新组件 EditCaretPositioning.js具有 2 个功能:(1) saveSelection 保存插入符位置,(2) restoreSelection 恢复插入符位置。
  2. 保存插入符位置在Input的状态组件
  3. 调用saveSelection()在每次改变事件之后
  4. restoreSelection()作为设置状态后的回调
  5. 已添加 id<div>所以可以引用restoreSelection()功能

EditCaretPositioning.js

const EditCaretPositioning = {}

export default EditCaretPositioning;


if (window.getSelection && document.createRange) {
//saves caret position(s)
EditCaretPositioning.saveSelection = function(containerEl) {
var range = window.getSelection().getRangeAt(0);
var preSelectionRange = range.cloneRange();
preSelectionRange.selectNodeContents(containerEl);
preSelectionRange.setEnd(range.startContainer, range.startOffset);
var start = preSelectionRange.toString().length;

return {
start: start,
end: start + range.toString().length
}
};
//restores caret position(s)
EditCaretPositioning.restoreSelection = function(containerEl, savedSel) {
var charIndex = 0, range = document.createRange();
range.setStart(containerEl, 0);
range.collapse(true);
var nodeStack = [containerEl], node, foundStart = false, stop = false;

while (!stop && (node = nodeStack.pop())) {
if (node.nodeType === 3) {
var nextCharIndex = charIndex + node.length;
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
range.setStart(node, savedSel.start - charIndex);
foundStart = true;
}
if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
range.setEnd(node, savedSel.end - charIndex);
stop = true;
}
charIndex = nextCharIndex;
} else {
var i = node.childNodes.length;
while (i--) {
nodeStack.push(node.childNodes[i]);
}
}
}

var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}



} else if (document.selection && document.body.createTextRange) {
//saves caret position(s)
EditCaretPositioning.saveSelection = function(containerEl) {
var selectedTextRange = document.selection.createRange();
var preSelectionTextRange = document.body.createTextRange();
preSelectionTextRange.moveToElementText(containerEl);
preSelectionTextRange.setEndPoint("EndToStart", selectedTextRange);
var start = preSelectionTextRange.text.length;

return {
start: start,
end: start + selectedTextRange.text.length
}
};
//restores caret position(s)
EditCaretPositioning.restoreSelection = function(containerEl, savedSel) {
var textRange = document.body.createTextRange();
textRange.moveToElementText(containerEl);
textRange.collapse(true);
textRange.moveEnd("character", savedSel.end);
textRange.moveStart("character", savedSel.start);
textRange.select();
};

}

更新的 contentEditable div 组件:

import CaretPositioning from 'EditCaretPositioning'

class Input extends Component {

constructor(props) {
super(props);
this.state = {
//newValue input by user
newValue : undefined,
//stores positions(s) of caret to handle reload after onChange end
caretPosition : {
start : 0,
end : 0
}
}
}

//handler during key press / input
onChangeHandler = event => {
let targetValue = event.currentTarget.textContent;
//save caret position(s), so can restore when component reloads
let savedCaretPosition = CaretPositioning.saveSelection(event.currentTarget);
this.setState({
"newValue": targetValue,
"caretPosition" : savedCaretPosition
}, () => {
//restore caret position(s)
CaretPositioning.restoreSelection(document.getElementById("editable"), this.state.caretPosition);
})
}

//handler when user opens input form
onBlurHandler = event => {
//some code that sends the "newValue" to be saved, and resets state
}

render() {
//determine which value to show in the div
let showValue;
//if there is a new value being input by user, show this value
if (this.state.newValue !== undefined) {
showValue = this.state.newValue;
} else {
//if prop has no value e.g. null or undefined, use "" placeholder
if (this.props.value) {
showValue = this.props.value;
} else {
showValue = "";
}
}

return (
<table>
<tbody>
<td>
<div
id="editable"
contentEditable="true"
suppressContentEditableWarning="true"
onInput={this.onChangeHandler.bind(this)}
onBlur={this.onBlurHandler}
>{showValue}
</div>
</td>
</tbody>
</table>
)
}
}

export default Input;

关于javascript - react : How to maintain caret position when editing contentEditable div?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55881397/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com