为什么在安卓设备上,如果在`navigator.clipboard.writeText`之前有`alert()`,它就无法成功复制文本到剪贴板?
<p>当尝试在安卓的Chrome浏览器上使用<code>navigator.clipboard.writeText()</code>复制一些文本时,只要我之后不显示警告框,它就能正常工作。一旦我显示了一个alert(),它就不再工作了。</p>
<p>例如,下面的代码按预期工作正常:</p>
<p><br /></p>
<pre class="brush:js;toolbar:false;">function myFunction() {
var copyText = document.getElementById("myInput");
copyText.select();
copyText.setSelectionRange(0, 99999);
navigator.clipboard.writeText(copyText.value);
}</pre>
<pre class="brush:html;toolbar:false;"><input type="text" value="Hello world" id="myInput" style="width:auto">
<button onclick="myFunction()">copy</button></pre>
<p><br /></p>
<p>然而下面的代码不起作用,在控制台中不会抛出任何错误,并且在PC上的Chrome浏览器上正常工作,但在安卓上不行。</p>
<p><br /></p>
<pre class="brush:js;toolbar:false;">function myFunction()
{
var copyText = document.getElementById("myInput");
copyText.select();
copyText.setSelectionRange(0, 99999);
navigator.clipboard.writeText(copyText.value);
alert("成功复制了文本")
}</pre>
<pre class="brush:html;toolbar:false;"><input type="text" value="Hello world" id="myInput" style="width:auto" >
<button onclick="myFunction()" >copy</button></pre>
<p><br /></p>
<p>有人知道发生了什么吗?谢谢。</p>
原因
navigator.clipboard.writetext不起作用的原因:兼容性问题:在废弃了
document.exec("copy")方法后,此方法是后来添加的。在 某些浏览器版本 中,此方法将不起作用,您应该检查此方法是否可用。文档未聚焦:如果您在没有任何用户交互的情况下将内容写入剪贴板,浏览器将阻止您的请求,并在此方法的 Promise 中抛出错误。想象一下,用户想要复制一个您从互联网上加载的字符串(
ajax)。如果此ajax请求花费了一点时间,浏览器的焦点将会过期,我的经验是无法完成复制。未授权的权限:有时用户可能通过编辑其隐私和安全设置来阻止浏览器自动复制到剪贴板。在进行复制之前,请检查写入剪贴板的权限。但是,当页面处于活动选项卡时,
clipboard-write权限会自动授予页面。异步问题:复制到剪贴板是一个异步操作,您应该等待您的代码完成工作。
HTTP 网站:此功能仅在安全上下文(HTTPS)中可用,在某些或所有支持的浏览器中。
Apple Safari 问题:苹果的 Clipboard API 大多数情况下期望一个
Promise在写入剪贴板时。因此,我们可以使用ClipboardItem将一个Promise传递给write方法。我建议您使用 write 而不是writeText说话容易,展示给我 代码:
function copy(text) { return new Promise((resolve, reject) => { if (typeof navigator !== "undefined" && typeof navigator.clipboard !== "undefined" && navigator.permissions !== "undefined") { const type = "text/plain"; const blob = new Blob([text], { type }); const data = [new ClipboardItem({ [type]: blob })]; navigator.permissions.query({name: "clipboard-write"}).then((permission) => { if (permission.state === "granted" || permission.state === "prompt") { navigator.clipboard.write(data).then(resolve, reject).catch(reject); } else { reject(new Error("Permission not granted!")); } }); } else if (document.queryCommandSupported && document.queryCommandSupported("copy")) { var textarea = document.createElement("textarea"); textarea.textContent = text; textarea.style.position = "fixed"; textarea.style.width = '2em'; textarea.style.height = '2em'; textarea.style.padding = 0; textarea.style.border = 'none'; textarea.style.outline = 'none'; textarea.style.boxShadow = 'none'; textarea.style.background = 'transparent'; document.body.appendChild(textarea); textarea.focus(); textarea.select(); try { document.execCommand("copy"); document.body.removeChild(textarea); resolve(); } catch (e) { document.body.removeChild(textarea); reject(e); } } else { reject(new Error("None of copying methods are supported by this browser!")); } }); }用法:
try { await copy("Hay yah!"); } catch(e) { console.error(e); }重要提示:通过按钮和
onclick事件进行测试,而不是在控制台中。因为
navigator.clipboard.writeText方法返回一个Promise,而你的代码没有等待它的结果。如果你按照下面的代码进行修正,应该就没问题了:
function myFunction() { var copyText = document.getElementById("myInput"); copyText.select(); copyText.setSelectionRange(0, 99999); navigator.clipboard .writeText(copyText.value) .then(() => { alert("成功复制"); }) .catch(() => { alert("出了点问题"); }); }有关
Promise和navigator.clipboard.writeText方法的更多信息,请访问以下链接:JavaScript.info上的Promise
MDN上与剪贴板交互