Javascript-将字符串以text/html的形式复制到剪贴板
Javascript - Copy string to clipboard as text/html
javascript中有没有一种方法可以将html字符串(即<b>xx<b>
)以text/html的形式复制到剪贴板中,这样它就可以粘贴到例如具有格式(即粗体xx)的gmail消息中
例如,存在将文本(text/plain)复制到剪贴板的解决方案https://stackoverflow.com/a/30810322/460084但不是text/html/
我需要一个非flash、非jquery的解决方案,它至少能在IE11 FF42和Chrome上运行。
理想情况下,我希望将字符串的文本和html版本都存储在剪贴板中,以便根据目标是否支持html来粘贴正确的字符串。
由于这个答案得到了一些关注,我已经完全重写了混乱的原始版本,以便更容易掌握。如果你想看一下修订前的版本,你可以在这里找到。
简单的问题:
我可以使用JavaScript将一些HTML代码的格式化输出复制到用户剪贴板吗?
答案:
是的,有一些限制,你可以。
解决方案:
下面是一个函数,它可以做到这一点。我用你需要的浏览器测试了它,它在所有浏览器中都能工作。然而,IE 11将要求确认这一行动。
下面可以解释它的工作原理,您可以在这个jsFiddle中交互式测试该函数。
// This function expects an HTML string and copies it as rich text.
function copyFormatted (html) {
// Create container for the HTML
// [1]
var container = document.createElement('div')
container.innerHTML = html
// Hide element
// [2]
container.style.position = 'fixed'
container.style.pointerEvents = 'none'
container.style.opacity = 0
// Detect all style sheets of the page
var activeSheets = Array.prototype.slice.call(document.styleSheets)
.filter(function (sheet) {
return !sheet.disabled
})
// Mount the container to the DOM to make `contentWindow` available
// [3]
document.body.appendChild(container)
// Copy to clipboard
// [4]
window.getSelection().removeAllRanges()
var range = document.createRange()
range.selectNode(container)
window.getSelection().addRange(range)
// [5.1]
document.execCommand('copy')
// [5.2]
for (var i = 0; i < activeSheets.length; i++) activeSheets[i].disabled = true
// [5.3]
document.execCommand('copy')
// [5.4]
for (var i = 0; i < activeSheets.length; i++) activeSheets[i].disabled = false
// Remove the container
// [6]
document.body.removeChild(container)
}
解释:
查看上面代码中的注释,查看您当前在以下过程中的位置:
- 我们创建一个容器来放入HTML代码
- 我们将容器设置为隐藏的样式,并检测页面的活动样式表。原因将很快解释
- 我们将容器放入页面的DOM中
- 我们删除可能存在的选择并选择容器的内容
我们自己复制。这实际上是一个多步骤的过程:Chrome将使用应用的CSS样式复制文本,而其他浏览器将使用浏览器的默认样式复制文本。因此,我们将在复制之前禁用所有用户样式,以获得尽可能一致的结果。
- 在执行此操作之前,我们会提前执行
copy
命令。这是针对IE11的黑客攻击:在这个浏览器中,复制必须手动确认一次。直到用户点击"确认"按钮,IE用户才会看到没有任何样式的页面。为了避免这种情况,我们先复制,等待确认,然后禁用样式并再次复制。那一次我们不会得到一个确认对话框,因为IE记得我们最后的选择 - 我们实际上禁用了页面的样式
- 现在我们再次执行
copy
命令 - 我们重新启用样式表
- 在执行此操作之前,我们会提前执行
- 我们从页面的DOM中移除容器
我们完了。
注意事项:
格式化后的内容在浏览器之间不会完全一致。
如上所述,Chrome(即Blink引擎)将使用与Firefox和IE不同的策略:Chrome将使用其CSS样式复制内容,但省略任何未定义的样式。
另一方面,Firefox和IE不会应用特定页面的CSS,而是应用浏览器的默认样式。这也意味着它们会应用一些奇怪的样式,例如默认字体(通常是Times New Roman)。
出于安全原因,浏览器只允许该功能作为用户交互(如点击、按键等)的效果执行
有一个简单得多的解决方案。复制页面(元素)的一部分,而不是复制HTML。
通过这个简单的功能,您可以将页面上或整个文档上想要的任何内容(文本、图像、表格等)复制到剪贴板。函数接收元素id或元素本身。
function copyElementToClipboard(element) {
window.getSelection().removeAllRanges();
let range = document.createRange();
range.selectNode(typeof element === 'string' ? document.getElementById(element) : element);
window.getSelection().addRange(range);
document.execCommand('copy');
window.getSelection().removeAllRanges();
}
如何使用:
copyElementToClipboard(document.body);
copyElementToClipboard('myImageId');
对于那些正在寻找使用ClipboardItem实现这一目标的方法,并且即使将dom.events.asyncClipboard.ClipboardItemset为true也无法使其工作的人,可以在nikousitalo.com上找到答案。
这是我的工作代码(在Firefox 102上测试)。
const clipboardItem = new
ClipboardItem({'text/html': new Blob([html],
{type: 'text/html'}),
'text/plain': new Blob([html],
{type: 'text/plain'})});
navigator.clipboard.write([clipboardItem]).
then(_ => console.log("clipboard.write() Ok"),
error => alert(error));
请确保尝试将其粘贴到富文本编辑器(如gmail)中,而不是粘贴到纯文本/标记编辑器(如stackoverflow)中。
如果您想使用新的剪贴板API,请使用下面的write
方法:
var type = "text/html";
var blob = new Blob([text], { type });
var data = [new ClipboardItem({ [type]: blob })];
navigator.clipboard.write(data).then(
function () {
/* success */
},
function () {
/* failure */
}
);
目前(2021年9月),问题是Firefox不支持这种方法。
我对Loilo上面的答案做了一些修改:
-
将焦点设置(稍后恢复)到隐藏的div可以防止FF在从文本区域复制时进入无休止的递归
-
将范围设置为div的内部子级可防止chrome在开始的中插入额外的
<br>
-
getSelection()上的removeAllRanges阻止附加到现有选择(可能不需要)
-
try/catch around execCommand
-
隐藏副本div更好的
在OSX上,这将不起作用。Safari不支持execCommand,chrome OSX存在已知错误https://bugs.chromium.org/p/chromium/issues/detail?id=552975
代码:
clipboardDiv = document.createElement('div');
clipboardDiv.style.fontSize = '12pt'; // Prevent zooming on iOS
// Reset box model
clipboardDiv.style.border = '0';
clipboardDiv.style.padding = '0';
clipboardDiv.style.margin = '0';
// Move element out of screen
clipboardDiv.style.position = 'fixed';
clipboardDiv.style['right'] = '-9999px';
clipboardDiv.style.top = (window.pageYOffset || document.documentElement.scrollTop) + 'px';
// more hiding
clipboardDiv.setAttribute('readonly', '');
clipboardDiv.style.opacity = 0;
clipboardDiv.style.pointerEvents = 'none';
clipboardDiv.style.zIndex = -1;
clipboardDiv.setAttribute('tabindex', '0'); // so it can be focused
clipboardDiv.innerHTML = '';
document.body.appendChild(clipboardDiv);
function copyHtmlToClipboard(html) {
clipboardDiv.innerHTML=html;
var focused=document.activeElement;
clipboardDiv.focus();
window.getSelection().removeAllRanges();
var range = document.createRange();
range.setStartBefore(clipboardDiv.firstChild);
range.setEndAfter(clipboardDiv.lastChild);
window.getSelection().addRange(range);
var ok=false;
try {
if (document.execCommand('copy')) ok=true; else utils.log('execCommand returned false !');
} catch (err) {
utils.log('execCommand failed ! exception '+err);
}
focused.focus();
}
请参阅jsfiddle,在那里您可以在文本区域中输入html片段,并使用ctrl+c复制到剪贴板。
- 零剪贴板复制文本后切换页面
- 复制到剪贴板在safari-angularjs中不起作用
- 使用javascript代码将HTML元素复制到剪贴板
- “复制到剪贴板”不起作用
- 使用jQuery/Javascript将忽略表头的表的内容复制到剪贴板
- javascript中的复制到剪贴板功能
- 将属性模型复制到剪贴板
- WinJs 复制到 Windows Phone 的剪贴板
- JavaScript 自动将文本复制到剪贴板
- 只能在第二次单击时将副本复制到剪贴板
- 复制到剪贴板是't工作
- c#在浏览器SharePoint中将文本框的内容复制到剪贴板
- 如何使用jquery将多个按钮ID复制到剪贴板
- 复制到剪贴板在firefox25中不起作用
- jQuery zClip 不会将值复制到剪贴板
- 为什么一个值没有在javascript中复制到剪贴板
- 如何在Webkit中将基于画布的图形复制到剪贴板
- 如何在使用之前检测复制到剪贴板的功能
- AppJs 键盘快捷键(复制、粘贴、剪贴板、退出、全选...
- 如何编辑此代码HTML/CSS以使'选择'JS代码也复制2剪贴板