如何只访问 'input' 事件的更改数据,而不管文本删除或插入(如后者的粘贴、键入或恢复文本)?
How to access just the changed data of an 'input' event regardless of text deletion or insertion like pasted or typed or restored text for the latter?
我有一个文本区域,想要 return 对文本的最新更改以用于 avia JavaScript 功能。这将包括:
- 通过键盘输入、粘贴或通过小部件(也许是 oninput?)插入的文本
- 通过退格、删除、ctrl + 退格等方式删除的文本
例如:
- 如果用户按下“a”,这就是我想要的return。
- 如果他们粘贴“苹果”,我想要整个粘贴的短语。
- 如果他们按下退格键并删除“h”,我想要 returned。
- 如果他们突出显示“马”并按删除,
我对此还是个新手,完全不知道如何调用 added/removed 文本以在 JavaScript 函数中使用。
阅读关于 InputEvent
, InputEvent.inputType
and InputEvent.data
might be a good starting point. In combination with selectionStart
/ selectionEnd
as with e.g. HTMLInputElement
s and/or HTMLTextAreaElement
的文章几乎可以 cover/solve OP 的任务。
检测输入中(文本)变化的可能方法 data/value 可能...
利用WeakMap
实例作为文本区域and/orinput-element基于存储 此类元素的最新(文本)值。
通过跟踪此类元素的 'input'
事件 启用对 data/value 更改的精确检测,基于最近和当前(文本)值以及 selectionEnd
,有时基于输入事件的 data
值。
如果已验证基于 input-event 的 text-value 更改 将创建并调度 custom event。因此现在可以直接监听和处理textarea and/or input-element相关的'input:datachange'
事件.
在新的自定义 'input:datachange'
事件类型之上,'input'
和 'change'
事件都不会收到所有附加信息,OP现在将能够直接访问更改的值,无论是删除and/or插入(后者是粘贴、输入或恢复)。
// the node reference based storage of most recent element values.
const mostRecentValueStorage = new WeakMap;
function getDataChangeFromDeleteOrPaste({ currentTarget, data }) {
const recentValue = mostRecentValueStorage.get(currentTarget);
const { value: currentValue, selectionEnd } = currentTarget;
let deletionStart = selectionEnd;
let leadingValue = currentValue.slice(0, deletionStart);
while ((leadingValue !== '') && !recentValue.startsWith(leadingValue)) {
leadingValue = leadingValue.slice(0, --deletionStart);
}
const deletionLength =
(selectionEnd - deletionStart) + (recentValue.length - currentValue.length);
const deleted = recentValue.slice(deletionStart, (deletionStart + deletionLength));
const insertLength = currentValue.length + deleted.length - recentValue.length;
const insertStart = selectionEnd - insertLength;
const inserted = (insertStart < selectionEnd)
&& currentValue.slice(insertStart, selectionEnd)
|| null;
return {
currentValue,
recentValue,
deleted: (deleted === '') ? null : deleted,
deletionStart: (deleted === '') ? null : deletionStart,
deletionLength: (deleted === '') ? null : deletionLength,
inserted,
insertStart: (inserted === null) ? null : insertStart,
insertLength: (inserted === null) ? null : insertLength,
};
}
function getDataChangeFromInsertText({ currentTarget, data }) {
const recentValue = mostRecentValueStorage.get(currentTarget);
const { value: currentValue, selectionEnd } = currentTarget;
const insertLength = data.length;
const deletionStart = (selectionEnd - insertLength);
const deletionLength = (recentValue.length - currentValue.length + insertLength);
const deleted = recentValue.slice(deletionStart, (deletionStart + deletionLength));
return {
currentValue,
recentValue,
deleted: (deleted === '') ? null : deleted,
deletionStart: (deleted === '') ? null : deletionStart,
deletionLength: (deleted === '') ? null : deletionLength,
inserted: data,
insertStart: (selectionEnd - insertLength),
insertLength,
};
}
function handleCustomInputDataChange(evt) {
const { currentTarget } = evt;
if (currentTarget.value !== mostRecentValueStorage.get(currentTarget)) {
const { data } = evt;
const dataChange = (
(typeof data === 'string') && getDataChangeFromInsertText(evt)
) || (
(data === null) && getDataChangeFromDeleteOrPaste(evt)
) || null;
// put the most recent element value into an object based storage.
mostRecentValueStorage.set(currentTarget, currentTarget.value);
currentTarget
.dispatchEvent(
new CustomEvent('input:datachange', {
bubbles: true,
detail: {
dataChange,
inputEvent: evt,
},
})
);
}
}
function enableCustomInputDataChangeHandling(elmNode) {
// put the initial element value into an object based storage.
mostRecentValueStorage.set(elmNode, elmNode.defaultValue);
elmNode
.addEventListener('input', handleCustomInputDataChange);
}
function initializeCustomInputDataChangeHandling() {
document
// for every element which features a
// `data-handle-input-data-change` attribute ...
.querySelectorAll('[data-handle-input-data-change]')
// ... enable the handling of a custom
// 'input:datachange' event.
.forEach(enableCustomInputDataChangeHandling);
}
function main() {
initializeCustomInputDataChangeHandling();
document
// subscribe to the custom 'input:datachange' event wherever it is needed.
.addEventListener(
'input:datachange',
({ target, detail: { dataChange } }) => console.log({ /*target, */dataChange })
);
}
main();
body { margin: 0; }
.as-console-wrapper { left: auto!important; width: 76%; min-height: 100%!important; }
<textarea
data-handle-input-data-change
cols="16"
rows="12"
>The quick brown fox jumps over the lazy dog ... edit text in whichever way.</textarea>
我有一个文本区域,想要 return 对文本的最新更改以用于 avia JavaScript 功能。这将包括:
- 通过键盘输入、粘贴或通过小部件(也许是 oninput?)插入的文本
- 通过退格、删除、ctrl + 退格等方式删除的文本
例如:
- 如果用户按下“a”,这就是我想要的return。
- 如果他们粘贴“苹果”,我想要整个粘贴的短语。
- 如果他们按下退格键并删除“h”,我想要 returned。
- 如果他们突出显示“马”并按删除,
我对此还是个新手,完全不知道如何调用 added/removed 文本以在 JavaScript 函数中使用。
阅读关于 InputEvent
, InputEvent.inputType
and InputEvent.data
might be a good starting point. In combination with selectionStart
/ selectionEnd
as with e.g. HTMLInputElement
s and/or HTMLTextAreaElement
的文章几乎可以 cover/solve OP 的任务。
检测输入中(文本)变化的可能方法 data/value 可能...
利用
WeakMap
实例作为文本区域and/orinput-element基于存储 此类元素的最新(文本)值。通过跟踪此类元素的
'input'
事件 启用对 data/value 更改的精确检测,基于最近和当前(文本)值以及selectionEnd
,有时基于输入事件的data
值。如果已验证基于 input-event 的 text-value 更改 将创建并调度 custom event。因此现在可以直接监听和处理textarea and/or input-element相关的
'input:datachange'
事件.
在新的自定义 'input:datachange'
事件类型之上,'input'
和 'change'
事件都不会收到所有附加信息,OP现在将能够直接访问更改的值,无论是删除and/or插入(后者是粘贴、输入或恢复)。
// the node reference based storage of most recent element values.
const mostRecentValueStorage = new WeakMap;
function getDataChangeFromDeleteOrPaste({ currentTarget, data }) {
const recentValue = mostRecentValueStorage.get(currentTarget);
const { value: currentValue, selectionEnd } = currentTarget;
let deletionStart = selectionEnd;
let leadingValue = currentValue.slice(0, deletionStart);
while ((leadingValue !== '') && !recentValue.startsWith(leadingValue)) {
leadingValue = leadingValue.slice(0, --deletionStart);
}
const deletionLength =
(selectionEnd - deletionStart) + (recentValue.length - currentValue.length);
const deleted = recentValue.slice(deletionStart, (deletionStart + deletionLength));
const insertLength = currentValue.length + deleted.length - recentValue.length;
const insertStart = selectionEnd - insertLength;
const inserted = (insertStart < selectionEnd)
&& currentValue.slice(insertStart, selectionEnd)
|| null;
return {
currentValue,
recentValue,
deleted: (deleted === '') ? null : deleted,
deletionStart: (deleted === '') ? null : deletionStart,
deletionLength: (deleted === '') ? null : deletionLength,
inserted,
insertStart: (inserted === null) ? null : insertStart,
insertLength: (inserted === null) ? null : insertLength,
};
}
function getDataChangeFromInsertText({ currentTarget, data }) {
const recentValue = mostRecentValueStorage.get(currentTarget);
const { value: currentValue, selectionEnd } = currentTarget;
const insertLength = data.length;
const deletionStart = (selectionEnd - insertLength);
const deletionLength = (recentValue.length - currentValue.length + insertLength);
const deleted = recentValue.slice(deletionStart, (deletionStart + deletionLength));
return {
currentValue,
recentValue,
deleted: (deleted === '') ? null : deleted,
deletionStart: (deleted === '') ? null : deletionStart,
deletionLength: (deleted === '') ? null : deletionLength,
inserted: data,
insertStart: (selectionEnd - insertLength),
insertLength,
};
}
function handleCustomInputDataChange(evt) {
const { currentTarget } = evt;
if (currentTarget.value !== mostRecentValueStorage.get(currentTarget)) {
const { data } = evt;
const dataChange = (
(typeof data === 'string') && getDataChangeFromInsertText(evt)
) || (
(data === null) && getDataChangeFromDeleteOrPaste(evt)
) || null;
// put the most recent element value into an object based storage.
mostRecentValueStorage.set(currentTarget, currentTarget.value);
currentTarget
.dispatchEvent(
new CustomEvent('input:datachange', {
bubbles: true,
detail: {
dataChange,
inputEvent: evt,
},
})
);
}
}
function enableCustomInputDataChangeHandling(elmNode) {
// put the initial element value into an object based storage.
mostRecentValueStorage.set(elmNode, elmNode.defaultValue);
elmNode
.addEventListener('input', handleCustomInputDataChange);
}
function initializeCustomInputDataChangeHandling() {
document
// for every element which features a
// `data-handle-input-data-change` attribute ...
.querySelectorAll('[data-handle-input-data-change]')
// ... enable the handling of a custom
// 'input:datachange' event.
.forEach(enableCustomInputDataChangeHandling);
}
function main() {
initializeCustomInputDataChangeHandling();
document
// subscribe to the custom 'input:datachange' event wherever it is needed.
.addEventListener(
'input:datachange',
({ target, detail: { dataChange } }) => console.log({ /*target, */dataChange })
);
}
main();
body { margin: 0; }
.as-console-wrapper { left: auto!important; width: 76%; min-height: 100%!important; }
<textarea
data-handle-input-data-change
cols="16"
rows="12"
>The quick brown fox jumps over the lazy dog ... edit text in whichever way.</textarea>