我正在使用此功能将URL复制到剪贴板:
function CopyUrl($this){ var querySelector = $this.next().attr("id"); var emailLink = document.querySelector("#"+querySelector); var range = document.createRange(); range.selectNode(emailLink); window.getSelection().addRange(range); try { // Now that we've selected the anchor text, execute the copy command var successful = document.execCommand('copy', false, null); var msg = successful ? 'successful' : 'unsuccessful'; if(true){ $this.addClass("copied").html("Copied"); } } catch(err) { console.log('Oops, unable to copy'); } // Remove the selections - NOTE: Should use // removeRange(range) when it is supported window.getSelection().removeAllRanges(); }
在桌面浏览器上一切正常,但在我的函数成功返回的iOS设备上没有,但数据根本没有复制到剪贴板.造成这种情况的原因是什么?如何解决这个问题?
看起来在选择范围和一些小黑客的帮助下,可以直接复制到iOS(> = 10)Safari上的剪贴板.我个人在iPhone 5C iOS 10.3.3和iPhone 8 iOS 11.1上进行了测试.但是,似乎有一些限制,它们是:
只能从和
元素中复制文本.
如果持有文本的元素不在 a内,那么它必须是
contenteditable
.
拿着文本的元素一定不能是readonly
(虽然你可能会尝试,这不是一个"官方"的方法记录任何地方).
元素内的文本必须在选择范围内.
要涵盖所有这四个"要求",您必须:
将要复制的文本放在一个或
元素中.
保存元素的旧值contenteditable
以及readonly
复制后能够还原它们的元素.
更改contenteditable
到true
和readonly
到false
.
创建一个范围以选择所需的元素并将其添加到窗口的选择中.
设置整个元素的选择范围.
恢复以前的值contenteditable
和readonly
值.
跑execCommand('copy')
.
这将导致用户设备的插入符移动并选择所需元素中的所有文本,然后自动发出复制命令.用户将看到正在选择的文本,并且将显示带有选项/复制/粘贴选项的工具提示.
现在,这看起来有点复杂,只是发出一个复制命令太麻烦,所以我不确定这是Apple的预期设计选择,但是谁知道......同时,这当前有效在iOS> = 10.
有了这个说法,像这样的polyfill可用于简化此操作并使其跨浏览器兼容(感谢@Toskan在评论中的链接).
工作实例
总而言之,您需要的代码如下所示:
function iosCopyToClipboard(el) { var oldContentEditable = el.contentEditable, oldReadOnly = el.readOnly, range = document.createRange(); el.contentEditable = true; el.readOnly = false; range.selectNodeContents(el); var s = window.getSelection(); s.removeAllRanges(); s.addRange(range); el.setSelectionRange(0, 999999); // A big number, to cover anything that could be inside the element. el.contentEditable = oldContentEditable; el.readOnly = oldReadOnly; document.execCommand('copy'); }
请注意,el
此函数的参数必须是a 或a
.
在iOS <10上,对Clipboard API的 Safari(实际上是安全措施)有一些限制:
它copy
仅在有效选择上触发事件,cut
并且paste
仅在可聚焦的可编辑字段中触发事件.
它只支持通过快捷键读取/写入OS剪贴板,而不是通过document.execCommand()
.请注意,"shorcut键"表示一些可点击(例如复制/粘贴操作菜单或自定义iOS键盘快捷键)或物理键(例如连接的蓝牙键盘).
它不支持ClipboardEvent
构造函数.
因此(至少截至目前),不可能使用Javascript以编程方式在iOS设备上复制剪贴板中的某些文本/值.只有用户才能决定是否复制某些内容.
但是,可以通过编程方式选择某些内容,这样用户只需点击选择中显示的"复制"工具提示即可.这可以使用与上面完全相同的代码来实现,只需删除execCommand('copy')
,这实际上是行不通的.
我已经搜索了一些解决方案,我找到了一个实际可行的解决方案:http://www.seabreezecomputers.com/tips/copy2clipboard.htm
基本上,示例可能是这样的:
var $input = $(' some input/textarea '); $input.val(result); if (navigator.userAgent.match(/ipad|ipod|iphone/i)) { var el = $input.get(0); var editable = el.contentEditable; var readOnly = el.readOnly; el.contentEditable = 'true'; el.readOnly = 'false'; var range = document.createRange(); range.selectNodeContents(el); var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); el.setSelectionRange(0, 999999); el.contentEditable = editable; el.readOnly = readOnly; } else { $input.select(); } document.execCommand('copy'); $input.blur();
这是我的跨浏览器实现
您可以通过运行以下代码段进行测试
例:
copyToClipboard("Hello World");
copyToClipboard("Hello World");
/**
* Copy a string to clipboard
* @param {String} string The string to be copied to clipboard
* @return {Boolean} returns a boolean correspondent to the success of the copy operation.
*/
function copyToClipboard(string) {
let textarea;
let result;
try {
textarea = document.createElement('textarea');
textarea.setAttribute('readonly', true);
textarea.setAttribute('contenteditable', true);
textarea.style.position = 'fixed'; // prevent scroll from jumping to the bottom when focus is set.
textarea.value = string;
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
const range = document.createRange();
range.selectNodeContents(textarea);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
textarea.setSelectionRange(0, textarea.value.length);
result = document.execCommand('copy');
} catch (err) {
console.error(err);
result = null;
} finally {
document.body.removeChild(textarea);
}
// manual copy fallback using prompt
if (!result) {
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
const copyHotkey = isMac ? '?C' : 'CTRL+C';
result = prompt(`Press ${copyHotkey}`, string); // eslint-disable-line no-alert
if (!result) {
return false;
}
}
return true;
}
出于安全原因,iOS Safari仅允许容器document.execCommand('copy')
内的文本contentEditable
.
解决方法是检测iOS Safari并contentEditable
在执行前快速切换document.execCommand('copy')
.
以下函数应适用于所有浏览器/设备,并接受CSS Selector或HTMLElement:
function copyToClipboard(el) {
// resolve the element
el = (typeof el === 'string') ? document.querySelector(el) : el;
// handle iOS as a special case
if (navigator.userAgent.match(/ipad|ipod|iphone/i)) {
// save current contentEditable/readOnly status
var editable = el.contentEditable;
var readOnly = el.readOnly;
// convert to editable with readonly to stop iOS keyboard opening
el.contentEditable = true;
el.readOnly = true;
// create a selectable range
var range = document.createRange();
range.selectNodeContents(el);
// select the range
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
el.setSelectionRange(0, 999999);
// restore contentEditable/readOnly to original state
el.contentEditable = editable;
el.readOnly = readOnly;
}
else {
el.select();
}
// execute copy command
document.execCommand('copy');
}
input { font-size: 14px; font-family: tahoma; }
button { font-size: 14px; font-family: tahoma; }
请检查我的解决方案.
它适用于Safari(在iPhone 7和iPad上测试)和其他浏览器.
window.Clipboard = (function(window, document, navigator) { var textArea, copy; function isOS() { return navigator.userAgent.match(/ipad|iphone/i); } function createTextArea(text) { textArea = document.createElement('textArea'); textArea.value = text; document.body.appendChild(textArea); } function selectText() { var range, selection; if (isOS()) { range = document.createRange(); range.selectNodeContents(textArea); selection = window.getSelection(); selection.removeAllRanges(); selection.addRange(range); textArea.setSelectionRange(0, 999999); } else { textArea.select(); } } function copyToClipboard() { document.execCommand('copy'); document.body.removeChild(textArea); } copy = function(text) { createTextArea(text); selectText(); copyToClipboard(); }; return { copy: copy }; })(window, document, navigator); // How to use Clipboard.copy('text to be copied');
https://gist.github.com/rproenca/64781c6a1329b48a455b645d361a9aa3 https://fiddle.jshell.net/k9ejqmqt/1/
希望对你有所帮助.
问候.