我正在使用这个函数将一个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设备上我的函数成功返回,但数据根本没有复制到剪贴板上。是什么原因造成的?我该如何解决这个问题?
看起来,有了选择范围和一些小黑的帮助,就可以直接复制到iOS(>=10)Safari上的剪贴板。我亲自在iPhone 5c iOS 10.3.3和iPhone 8 iOS 11.1上测试了这一点。不过,似乎也有一些限制,这些限制是:
和
元素复制。
中,则它必须是ContentEditable
。readonly
(尽管您可以尝试,但这不是任何地方记录的“正式”方法)。要满足所有这四个“要求”,您必须:
或
元素中。contenteditable
和readonly
的旧值,以便能够在复制后还原它们。contenteditable
更改为true
并将readonly
更改为false
。ContentEditable
和ReadOnly
值。execcommand('copy')
。这将导致用户设备的插入符号移动并选择您想要的元素中的所有文本,然后自动发出copy命令。用户将看到正在选择的文本,并显示带有选择/复制/粘贴选项的工具提示。
现在,这看起来有点复杂,太麻烦了,只发出一个拷贝命令,所以我不确定这是苹果的设计选择,但谁知道...同时,这当前在iOS>=10上工作。
这样,像这样的polyfills就可以用来简化这个操作,并使它能够跨浏览器兼容(谢谢@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
参数必须是或
。
在iOS<10上,Safari对剪贴板API有一些限制(实际上是安全措施):
复制
事件,并且仅在聚焦的可编辑字段中激发剪切
和粘贴
事件。document.execcommand()
读/写操作系统剪贴板。注意,“快捷键”表示一些可点击的(例如复制/粘贴操作菜单或自定义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");
null
/**
* 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;
}
Demo: <button onclick="copyToClipboard('It works!\nYou can upvote my answer now :)') ? this.innerText='Copied!': this.innerText='Sorry :(' ">Click here</button>
<p>
<textarea placeholder="(Testing area) Paste here..." cols="80" rows="4"></textarea>
</p>