navigator.clipboard未定义。

182

为什么以下代码片段中 navigator.clipboard 总是为 undefined

Translated text:

Why is navigator.clipboard always undefined in the following snippet?

var clipboard = navigator.clipboard;
if (clipboard == undefined) {
    console.log('clipboard is undefined');
} else {
    clipboard.writeText('stuff to write').then(function() {
        console.log('Copied to clipboard successfully!');
    }, function() {
        console.error('Unable to write to clipboard. :-(');
    });
}

更多关于剪贴板API的内容可以在这里找到。

Chrome版本号:68.0.3440.106。

我确定这个曾经是可用的,但现在不行了。让人感到困惑的是,这张表格表明Chrome实现了剪贴板API(已经有一段时间了),但特定API方法的这张表格则表明API的所有方法都不支持??


10
该页面是从安全来源提供的吗? - Josh Lee
5
啊啊啊@JoshLee...这就是区别所在...源代码已经被保护了(可以通过https访问),但由于某些原因我一直在使用http访问...当我通过https访问时,clipboard对象可用!这解释了为什么我曾经确信它之前是可以工作的。也许我应该将所有http重定向到https。谢谢...如果你提交答案,我会将其标记为正确的。 - drmrbrewer
我曾经遇到过同样的问题,但是这里提供的解决方案并没有起作用。直到我发现文本区域或文本字段可能不应该被禁用! - Harm
8个回答

261

这需要一个安全的源 - 要么是HTTPS或localhost(或通过在Chrome中运行标志禁用)。与ServiceWorker一样,该状态由navigator对象上的属性的存在或不存在表示。

https://developers.google.com/web/updates/2018/03/clipboardapi

规范中使用[SecureContext]指示接口: https://w3c.github.io/clipboard-apis/#dom-navigator-clipboard

您可以检查window.isSecureContext的状态以了解功能不可用的原因。 安全上下文| MDN

是的,您应该设置HSTS,以确保HTTP重定向到HTTPS。


4
顺便提一句,禁用暂时的 HTTPS 检查标志是 --unsafely-treat-insecure-origin-as-secure=http://www.myexamplesite.com。 - RikiRiocma
30
chrome://flags中,启用“将不安全来源视为安全来源”,并提供您想要的源。 - Rokit
1
无论我尝试什么,都无法在 Chrome 无头模式下运行。 - danronmoon

134
您可以编写一个全能的包装函数。
  • 如果在安全上下文中(https):使用 navigator clipboard api
  • 如果不是:使用“视口外隐藏文本区域”技巧
async function copyToClipboard(textToCopy) {
    // Navigator clipboard api needs a secure context (https)
    if (navigator.clipboard && window.isSecureContext) {
        await navigator.clipboard.writeText(textToCopy);
    } else {
        // Use the 'out of viewport hidden text area' trick
        const textArea = document.createElement("textarea");
        textArea.value = textToCopy;
            
        // Move textarea out of the viewport so it's not visible
        textArea.style.position = "absolute";
        textArea.style.left = "-999999px";
            
        document.body.prepend(textArea);
        textArea.select();

        try {
            document.execCommand('copy');
        } catch (error) {
            console.error(error);
        } finally {
            textArea.remove();
        }
    }
}

使用方法:

try {
    await copyToClipboard("I'm going to the clipboard !");
    console.log('Text copied to the clipboard!');
} catch(error) {
    console.error(error);
}

PS:不要在类似jsfiddle/copeden/...这样的repl上尝试。

4
简洁地说: textArea.style.position = "absolute"; textArea.style.opacity = 0; 我认为调用焦点是不必要的。 - NanoNova
7
由于document.exeCommand已被弃用,因此没有其他方法。 - Colasanto
1
感谢您解释https上下文; 在其他示例中,这是一个神秘的阻止因素。 - Kalnode
不幸的是,我不断收到 DOMException: Document is not focused. 的错误信息 :( 它是从 Chrome 代码片段中调用的。 - Kamajabu

15

试试这个:

if (typeof (navigator.clipboard) == 'undefined') {
    console.log('navigator.clipboard');
    var textArea = document.createElement("textarea");
    textArea.value = linkToGo;
    textArea.style.position = "fixed";  //avoid scrolling to bottom
    document.body.appendChild(textArea);
    textArea.focus();
    textArea.select();

    try {
        var successful = document.execCommand('copy');
        var msg = successful ? 'successful' : 'unsuccessful';
        toastr.info(msg);
    } catch (err) {
        toastr.warning('Was not possible to copy te text: ', err);
    }

    document.body.removeChild(textArea)
    return;
}
navigator.clipboard.writeText(linkToGo).then(function () {
    toastr.info(`successful!`);
}, function (err) {
    toastr.warning('unsuccessful!', err);
});

1
document.execCommand('copy');已经过时。 - key

6
当HTTPS尚不可用且使用document.execCommand('copy')无效时,实现复制工具提示的最小解决方案。但需要用户手动选择和复制弹出框中显示的内容。
function copyToClipboard(text) {
    if(navigator.clipboard) {
        navigator.clipboard.writeText(text);
    }
    else{
        alert(text);
    }
}

我正在使用Chrome v105,无法选择警报文本 :( - leverglowh
你好,我刚在Ubuntu 22.04上测试了一下,版本号为105.0.5195.102,它可以正常工作。Chrome移除这个功能似乎有些奇怪。 - Laurent Lyaudet
也许你正在智能手机上使用Chrome浏览器,选择文本可能会很麻烦? - Laurent Lyaudet
1
可能与这个bug有关https://support.google.com/chrome/thread/9959602/text-selection-fails-in-alert-messages?hl=en我的文本实际上相当长,我使用了一个提示框 :) - leverglowh
alert()函数是如何为这个目的服务的? - Si8
显示剩余2条评论

5
在本地主机上,Chrome浏览器会屏蔽剪贴板。您可以通过以下路径检查此问题:
Chrome > 设置 > 隐私和安全 > 网站设置 > 查看跨站点存储的权限和数据,然后单击您的本地主机URL,该URL将在页面上提及,并检查剪贴板的权限。

2

似乎不再起作用了。 - key
美观的界面,它尝试了 3 种自动方法,如果它们失败了,它将显示一个手动警报。它可以通过一些重新设计来满足您的需求,但总体上它是我迄今为止看到的最好的解决方案(花了一个小时搜索)。 - Filip Happy
仅提供链接的答案在SO上不被视为有价值的。如果该答案是正确的,应将问题标记为重复。 - isherwood

0
const copy = (text: string) => {
  if (navigator.clipboard) {
    navigator.clipboard.writeText(text)
  } else {
    const input = document.createElement('textarea')
    input.value = text
    document.body.appendChild(input)
    input.select()
    document.execCommand('copy')
    document.body.removeChild(input)
  }
}

-4

你可以使用:

更改:

navigator.clipboard.writeText("Content")

使用 navigator['clipboard'].writeText("内容") 代替。


2
你提出的更改并不是真正的更改。这两行代码是相同的,它们做的事情也是一样的。只是用了不同的方式来指示浏览器执行相同的操作。 - 0xC0DEGURU
但在我的情况下,它是有效的。 - Lutfi Fahmani
可能是因为你通过https进行测试,所以它对你有效。正如上面的答案所提到的,这是由于一个不安全的(http)页面引起的。 - Dean Forant
可能是因为你通过https进行测试,所以它对你有效。正如上面的答案所提到的,这是由于一个不安全的(http)页面引起的。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接