- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 contenteditable
构建一个小型自定义编辑器div 上的属性。
默认情况下,当用户粘贴 HTML 内容时,HTML 会插入到 contenteditable
中div,我不想要。
为了解决这个问题,我使用了一个像这个问题建议的自定义粘贴处理程序:
Stop pasting html style in a contenteditable div only paste the plain text
editor.addEventListener("paste", (e) => {
e.preventDefault();
const text = e.clipboardData.getData('text/plain');
document.execCommand("insertText", false, text.replaceAll("\n", "<div><br></div>"));
})
到目前为止一切顺利。因为 execCommand
已弃用,我使用了替代方法,基本上是使用范围手动插入文本(去除 HTML)。
execCommand() is now obsolete, what's the alternative?
replace selected text in contenteditable div
editor.addEventListener("paste", (e) => {
e.preventDefault();
const text = (e.originalEvent || e).clipboardData.getData("text/plain");
const selection = window.getSelection();
selection.deleteFromDocument();
const range = selection.getRangeAt(0);
range.insertNode(document.createTextNode(text));
range.collapse();
});
直到我注意到撤消和重做命令在粘贴某些内容后不再起作用之前,它一直运行良好。这是因为在自定义粘贴事件中完成了 DOM 修改,这会破坏交易。
在寻找解决方案时,我发现了以下问题:
Allowing contenteditable to undo after dom modification
那里的第一个答案建议使用 execCommand
,已弃用,因此这不是一个好的解决方案。
第二个答案建议构建自定义撤消重做堆栈来手动处理所有这些事件。所以我选择了第二种解决方案。
我使用一个简单的数组来构建自定义撤消重做处理程序来存储版本。为此,我使用了 beforeinput
监听撤消和重做事件的事件。
editor.addEventListener("beforeinput", (e) => {
if (e.inputType === "historyUndo") {
e.preventDefault();
console.log("undo");
};
if (e.inputType === "historyRedo") {
e.preventDefault();
console.log("redo");
};
});
这对于撤消非常有效,但是,由于我阻止了默认设置,浏览器撤消/重做堆栈永远不会处于重做状态,所以 beforeinput
按 cmd + z
时永远不会触发监听器或 ctrl + z
在 window 上。
我也尝试过使用 input
结果相同的事件。
我已经搜索了其他解决方案来使用 JavaScript 处理撤消/重做事件,但是使用 keydown
构建自定义处理程序在这里没有选择,因为每个操作系统都使用不同的快捷方式,尤其是移动设备!
现在,有多种可能的解决方案可以解决我的问题,因此非常欢迎任何可行的解决方案。
有没有办法手动处理粘贴事件并将粘贴的明文插入文档,同时保留撤消/重做功能或手动实现对此类功能的替换?
尝试粘贴一些东西然后撤消,这是行不通的。
const editor = document.getElementById("editor");
editor.addEventListener("paste", (e) => {
e.preventDefault();
const text = (e.originalEvent || e).clipboardData.getData("text/plain").replaceAll("\n", "<div><br></div>");
const selection = window.getSelection();
selection.deleteFromDocument();
const range = selection.getRangeAt(0);
range.insertNode(document.createTextNode(text));
range.collapse();
});
#editor {
border: 1px solid black;
height: 100px;
}
<div id="editor" contenteditable="true"></div>
修改 ClipboardEvent
不起作用,因为它是只读的。调度新事件也不起作用,因为该事件不受信任,因此浏览器不会粘贴内容。
const event = new ClipboardEvent("paste", {
clipboardData: new DataTransfer(),
});
event.clipboardData.setData("text/plain", "blah");
editor.dispatchEvent(event);
最佳答案
我面临同样的问题并使用 this writeup 中讨论的方法解决了它, 用他的原始代码 here .这是一个非常聪明的技巧。最后,他的方法仍然使用 execCommand
,但这是对 execCommand
的一种非常狭窄和隐藏的使用,只是为了将整数索引压入 native 撤消堆栈,以便您的“撤消数据”可以在单独的堆栈上进行跟踪。它还具有能够将正常的撤消操作(如恢复键入的输入)与您推送到单独的撤消堆栈的撤消操作穿插的好处。
我不得不修改他的撤消构造函数以使用“输入”元素而不是 contentEditable“div”。因为我已经在我自己的 contentEditable 'div' 中监听 'input',所以我需要对隐藏的输入 stopImmediatePropagation
。
constructor(callback, zero=null) {
this._duringUpdate = false;
this._stack = [zero];
// Using an input element rather than contentEditable div because parent is already a
// contentEditable div
this._ctrl = document.createElement('input');
this._ctrl.setAttribute('aria-hidden', 'true');
this._ctrl.setAttribute('id', 'hiddenInput');
this._ctrl.style.opacity = 0;
this._ctrl.style.position = 'fixed';
this._ctrl.style.top = '-1000px';
this._ctrl.style.pointerEvents = 'none';
this._ctrl.tabIndex = -1;
this._ctrl.textContent = '0';
this._ctrl.style.visibility = 'hidden'; // hide element while not used
this._ctrl.addEventListener('focus', (ev) => {
window.setTimeout(() => void this._ctrl.blur(), 1);
});
this._ctrl.addEventListener('input', (ev) => {
ev.stopImmediatePropagation(); // We don't want this event to be seen by the parent
if (!this._duringUpdate) {
callback(this.data);
this._ctrl.textContent = this._depth - 1;
} else {
this._ctrl.textContent = ev.data;
}
const s = window.getSelection();
if (s.containsNode(this._ctrl, true)) {
s.removeAllRanges();
}
});
}
我创建了撤消程序和一种捕获 undoerData 的方法,我正在使用它进行粘贴和其他需要在操作发生时访问该范围的操作。为了将其用于粘贴,我在我自己的 contentEditable div(下面称之为 editor
)中监听粘贴事件。
const undoer = new Undoer(_undoOperation, null);
const _undoerData = function(operation, data) {
const undoData = {
operation: operation,
range: _rangeProxy(), // <- Capture document.currentSelection() as a range
data: data
}
return undoData;
};
editor.addEventListener('paste', function(e) {
e.preventDefault();
var pastedText = undefined;
if (e.clipboardData && e.clipboardData.getData) {
pastedText = e.clipboardData.getData('text/plain');
}
const undoerData = _undoerData('pasteText', pastedText);
undoer.push(undoerData, editor);
_doOperation(undoerData);
});
然后 _doOperation
和 _undoOperation
开启操作并在 undoerData 中获取信息以采取适当的行动:
const _doOperation = function(undoerData) {
switch (undoerData.operation) {
case 'pasteText':
let pastedText = undoerData.data;
let range = undoerData.range;
// Do whatever is needed to paste the pastedText at the location
// identified in range
break;
default:
// Throw an error or do something reasonable
};
};
const _undoOperation = function(undoerData) {
switch (undoerData.operation) {
case 'pasteText':
let pastedText = undoerData.data;
let range = undoerData.range;
// Do whatever is needed to remove the pastedText at the location
// identified in range
break;
default:
// Throw an error or do something reasonable
};
};
通过此方案和实现的 pasteText 操作,您现在可以复制文本、粘贴 - 输入 - 删除文本 - 输入 - 重新定位光标 - 粘贴,然后撤消 6 次,在第 1 次和第 6 次撤消时调用 _undoOperation其他人只是按照他们应该的方式工作。
关于javascript - 如何在修改 DOM 后使自定义文本编辑器使用撤消和重做快捷方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66854679/
示例:我在 C 列中有一个公式,它是 A 和 B 列中值的函数。当我更改 A 或 B 中的值并按 Enter 键时,C 中的值会自动更新。但是,当我 Ctrl-Z 时,C 列中的值不会自动恢复到我更改
我使用 Eclipse 进行几乎所有语言的编程。我也喜欢用于快速编辑的 vim 快捷方式,所以我安装了 vrapper。问题是当我写了很多代码,我只想撤消一些小东西。它撤消了很多代码块,而不是 2 或
假设我们无意中将命名分支( ABC ) merge 到我们的 default 中。分支。 hg rollback不是一个选择,因为从那以后有几次提交。 有没有办法撤销这个? 最佳答案 您将需要 Mq
有什么办法可以实现这一点吗?我正在使用一个分页插件,它读取 ul 中的 li 数量,并确定要吐出的编号链接的数量。 最佳答案 您可能想使用 .hide() 并检查 li 是否可见。 这可以通过以下方式
我需要能够检测是否触发了“撤销”,以及它是否对我的 RichTextBox 的内容产生了影响。 当我在 RichTextBox 中键入内容,然后按 Ctrl+Z 时,windows 似乎会为我处理撤消
我的每个 php 页面的顶部都有以下代码: foreach ($_POST as $key => $value) { if (!is_array($value)) {
我正在为一个类的项目工作,我们应该在该类中实现文本编辑器的基本功能,包括撤消和重做。我目前的撤消/重做功能正常工作,唯一的问题是,我在尝试从 Command 中释放内存时遇到 valgrind 错误。
假设我有以下两个变量: bob1 = u'bob\xf0\xa4\xad\xa2' bob2 = 'bob\xf0\xa4\xad\xa2' 如何让 bob1 的值成为 bob2 的值?也就是说,我如
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 1 年前。 社区在 1 年前 审查了是否重
我已经成功地实现了 touchesMoved 并且它正在正确地绘制线条,现在我在实现删除方法时遇到了问题,请在我缺少的地方帮助我。 - (void)touchesMoved:(NSSet *)touc
我使用的是 Visual Studio 2015。TFS 的版本是 2012(版本 11.0.51106.1)。有没有办法撤销 unshelve,其他用户的 shelfset,有 unshelve 命
我正在使用 intelliJ 在功能分支上工作,我想将我的团队在 master 上所做的更改集成到我的分支中,但我搞砸了。 我检查了 master,从 Git pop 窗口中我选择了功能分支并选择了“
我的情况:我克隆了一个存储库(内核的源文件)。然后检查了一个分支,并构建了内核。二进制文件已存储在工作树的子目录中。现在,我想放弃所有本地更改,包括构建的二进制文件,并恢复到克隆存储库的不同分支。 我
我正在使用 SourceTree,我在“工作副本更改”部分下有一些修改过的文件,这些文件正在被跟踪,如图中的黄色图标所示。但我放弃了这些变化。现在如何恢复这些更改? 最佳答案 如果项目未暂存(在顶部
撤消特定提交的最简单方法是: 不在头部或头部 已推送到远程。 因为如果不是最新的提交, git reset HEAD 没用。并且因为它已经被推送到远程, git rebase -i 和 git reb
我有一个 Pdf 文件,每页包含几张幻灯片,包括文本(不仅是图像)。 该 pdf 可能是使用 pdfnup 创建的。 我可以恢复 pdfnup 操作,以便每张幻灯片都显示在一页上吗? 最佳答案 据我所
我正在进行合并。合并后,我提交所有文件而没有冲突。然后我解析单个文件并提交它们。如果我犯了一个错误,我该如何重做解析(即使我还没有提交解析文件)? 与预期相反,我无法还原文件。合并后恢复到任何步骤时,
当之后进行了 17 次提交时,如何撤消不应该进行的提交? 背景:我团队的一个同事单独工作了一个月,现在是时候将他们的分支 merge 到 master 上了。但是,其中一个提交包含一个太大的文件,无法
我正在尝试使用Command Pattern在我的应用程序中实现撤消/重做功能。我遇到了一个问题。 为了说明这一点,让我们假设您可以使用我的应用程序2D配置文件创建(任意数量)。 然后,可以从这些2D
我有一个工作流,我将描述如下: [ Dump(query) ] ---+ | +---> [ Parquet(d
我是一名优秀的程序员,十分优秀!