- 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/
好的,所以我编辑了以下... 只需将以下内容放入我的 custom.css #rt-utility .rt-block {CODE HERE} 但是当我尝试改变... 与 #rt-sideslid
在表格 View 中,我有一个自定义单元格(在界面生成器中高度为 500)。在该单元格中,我有一个 Collection View ,我按 (10,10,10,10) 固定到边缘。但是在 tablev
对于我的无能,我很抱歉,但总的来说,我对 Cocoa、Swift 和面向对象编程还很陌生。我的主要来源是《Cocoa Programming for OS X》(第 5 版),以及 Apple 的充满
我正在使用 meta-tegra 为我的 NVIDIA Jetson Nano 构建自定义图像。我需要 PyTorch,但没有它的配方。我在设备上构建了 PyTorch,并将其打包到设备上的轮子中。现
在 jquery 中使用 $.POST 和 $.GET 时,有没有办法将自定义变量添加到 URL 并发送它们?我尝试了以下方法: $.ajax({type:"POST", url:"file.php?
Traefik 已经默认实现了很多中间件,可以满足大部分我们日常的需求,但是在实际工作中,用户仍然还是有自定义中间件的需求,为解决这个问题,官方推出了一个 Traefik Pilot[1] 的功
我想让我的 CustomTextInputLayout 将 Widget.MaterialComponents.TextInputLayout.OutlinedBox 作为默认样式,无需在 XML 中
我在 ~/.emacs 中有以下自定义函数: (defun xi-rgrep (term) (grep-compute-defaults) (interactive "sSearch Te
我有下表: 考虑到每个月的权重,我的目标是在 5 个月内分散 10,000 个单位。与 10,000 相邻的行是我最好的尝试(我在这上面花了几个小时)。黄色是我所追求的。 我试图用来计算的逻辑如下:计
我的表单中有一个字段,它是文件类型。当用户点击保存图标时,我想自然地将文件上传到服务器并将文件名保存在数据库中。我尝试通过回显文件名来测试它,但它似乎不起作用。另外,如何将文件名添加到数据库中?是在模
我有一个 python 脚本来发送电子邮件,它工作得很好,但问题是当我检查我的电子邮件收件箱时。 我希望该用户名是自定义用户名,而不是整个电子邮件地址。 最佳答案 发件人地址应该使用的格式是: You
我想减小 ggcorrplot 中标记的大小,并减少文本和绘图之间的空间。 library(ggcorrplot) data(mtcars) corr <- round(cor(mtcars), 1)
GTK+ noob 问题在这里: 是否可以自定义 GtkFileChooserButton 或 GtkFileChooserDialog 以删除“位置”部分(左侧)和顶部的“位置”输入框? 我实际上要
我正在尝试在主页上使用 ajax 在 magento 中使用 ajax 显示流行的产品列表,我可以为 5 或“N”个产品执行此操作,但我想要的是将分页工具栏与结果集一起添加. 这是我添加的以显示流行产
我正在尝试使用 PasswordResetForm 内置函数。 由于我想要自定义表单字段,因此我编写了自己的表单: class FpasswordForm(PasswordResetForm):
据我了解,新的 Angular 7 提供了拖放功能。我搜索了有关 DnD 的 Tree 组件,但没有找到与树相关的内容。 我在 Stackblitz 上找到的一个工作示例.对比drag'ndrop功能
我必须开发一个自定义选项卡控件并决定使用 WPF/XAML 创建它,因为我无论如何都打算学习它。完成后应该是这样的: 到目前为止,我取得了很好的进展,但还有两个问题: 只有第一个/最后一个标签项应该有
我要定制xtable用于导出到 LaTeX。我知道有些问题是关于 xtable在这里,但我找不到我要找的具体东西。 以下是我的表的外观示例: my.table <- data.frame(Specif
用ejs在这里显示日期 它给我结果 Tue Feb 02 2016 16:02:24 GMT+0530 (IST) 但是我需要表现为 19th January, 2016 如何在ejs中执行此操作?
我想问在 JavaFX 中使用自定义对象制作 ListView 的最佳方法,我想要一个每个项目如下所示的列表: 我搜了一下,发现大部分人都是用细胞工厂的方法来做的。有没有其他办法?例如使用客户 fxm
我是一名优秀的程序员,十分优秀!