ChatGPT解决这个技术问题 Extra ChatGPT

在 iOS 中使用 Javascript 复制到剪贴板

我正在使用此函数将 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 设备上却不行,我的函数成功返回,但数据根本没有复制到剪贴板。是什么原因造成的,我该如何解决这个问题?


p
pgsandstrom

更新! iOS >= 10

看起来在选择范围和一些小技巧的帮助下,可以直接复制到 iOS (>= 10) Safari 上的剪贴板。我亲自在 iPhone 5C iOS 10.3.3 和 iPhone 8 iOS 11.1 上进行了测试。但是,似乎有一些限制,它们是:

文本只能从

注意:当它不是由用户发起时,它不起作用,比如超时或任何异步事件!它必须来自受信任的事件,例如从按钮上的单击事件调用


适用于我在 safari ios 和 chrome web 上测试。
为我在 Edge 上工作,尚未在 iOS 上测试
建议:从建议的解决方案中删除 textarea.focus(); - 否则它会向下滚动,无论设置 textarea.style.position = 'fixed';
当它不是来自像点击事件这样的可信事件时,知道如何做到这一点吗?
J
John Doherty

问题: iOS Safari 仅允许 document.execCommand('copy') 用于 contentEditable 容器中的文本。

解决方案:检测 iOS Safari 并在执行 document.execCommand('copy') 之前快速切换 contentEditable

以下功能适用于所有浏览器。使用 CSS 选择器或 HTMLElement 调用:

function copyToClipboard(el) { // 解析元素 el = (typeof el === 'string') ? document.querySelector(el) : el; // 将 iOS 作为特殊情况处理 if (navigator.userAgent.match(/ipad|ipod|iphone/i)) { // 保存当前的 contentEditable/readOnly 状态 var editable = el.contentEditable; var readOnly = el.readOnly; // 使用只读转换为可编辑以停止 iOS 键盘打开 el.contentEditable = true; el.readOnly = 真; // 创建一个可选择的范围 var range = document.createRange(); range.selectNodeContents(el); // 选择范围 var selection = window.getSelection(); selection.removeAllRanges();选择.addRange(范围); el.setSelectionRange(0, 999999); // 将 contentEditable/readOnly 恢复到原始状态 el.contentEditable = editable; el.readOnly = 只读; } 其他 { el.select(); } // 执行复制命令 document.execCommand('copy'); } 输入 { 字体大小:14px;字体系列:tahoma; } 按钮 { 字体大小:14px;字体系列:tahoma; }


注意:在使用 iOS 10 时,我发现上述方法还有一些额外的注意事项11. a) 输入需要有足够的宽度。如果您希望复制用户看不到的输入,则在 CSS 中设置宽度为零或 1px 将不起作用。 (有多大?谁知道?)在屏幕外设置一个相对位置似乎仍然没问题。 b) 如果您向其中添加 event.preventDefault(),请注意它会导致键盘输入(或表单导航输入?)弹出窗口切换,从而抵消使用 readOnly 的效果。希望对其他人有所帮助!
R
Rodrigo

请检查我的解决方案。

它适用于 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/

希望对您有所帮助。

问候。


E
Eric Seastrand

我的解决方案是通过结合此页面中的其他答案创建的。

与其他答案不同,它不需要您在页面上已有元素。它将创建自己的文本区域,然后清理混乱。

function copyToClipboard(str) {
    var el = document.createElement('textarea');
    el.value = str;
    el.setAttribute('readonly', '');
    el.style = {position: 'absolute', left: '-9999px'};
    document.body.appendChild(el);

    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(); 
    }

    document.execCommand('copy');
    document.body.removeChild(el);
}

@Jonah 请让我知道此页面上的其他解决方案中的哪一个对您有用。这样我就可以改进我的答案来帮助别人。
嘿,埃里克,实际上他们都没有。我已经尝试了一切,并且在 safari 上的 iphone(我在 ios 12 上)上不可能做到这一点。如果我不正确,请 lmk - 我想要一个解决方案 - 并且可能会在一个可行的解决方案中发布一个小提琴,我会在我的手机上进行测试。
@EricSeastrand 我正在尝试实施此解决方案和 range.selectNodeContents(el);已折叠我认为如果该范围已折叠,则在执行副本时实际上并未选择任何内容我的 el 是带有 defaultValue 的输入类型 =“文本”,您对此有什么了解吗?
@Jonah 我在 IOS 12 版本上面临同样的问题。你找到任何解决方案了吗?
不,iirc这是不可能的。
n
nfagerlund

iOS 13.4 及更新版本

从 13.4 版开始,iOS Safari 支持现代异步剪贴板 API:

MDN:剪贴板 API

我可以使用:clipboard.writeText

与 JavaScript 中的所有内容一样,较新的 API 大约好 1000 倍,但您仍然需要大量的后备代码,因为您的许多用户将使用旧版本多年。

以下是如何将新的剪贴板 API 与原始问题中的代码一起使用:

function CopyUrl($this){
  var querySelector = $this.next().attr("id");
  var emailLink = document.querySelector("#"+querySelector);

  if (navigator.clipboard) {
    var myText = emailLink.textContent;
    navigator.clipboard.writeText(myText).then(function() {
      // Do something to indicate the copy succeeded
    }).catch(function() {
      // Do something to indicate the copy failed
    });
  } else {
    // Here's where you put the fallback code for older browsers.
  }
}

这可行,但因为我在远程主机上开发,所以需要安全连接 https 才能拥有 navigator.clipboard - stackoverflow.com/questions/51805395/…
K
Kevin K.

不错,这是上面的打字稿重构,以防万一有人感兴趣(写为 ES6 模块):

type EditableInput = HTMLTextAreaElement | HTMLInputElement;

const selectText = (editableEl: EditableInput, selectionStart: number, selectionEnd: number) => {
    const isIOS = navigator.userAgent.match(/ipad|ipod|iphone/i);
    if (isIOS) {
        const range = document.createRange();
        range.selectNodeContents(editableEl);

        const selection = window.getSelection(); // current text selection
        selection.removeAllRanges();
        selection.addRange(range);
        editableEl.setSelectionRange(selectionStart, selectionEnd);
    } else {
        editableEl.select();
    }
};

const copyToClipboard = (value: string): void => {
    const el = document.createElement('textarea'); // temporary element
    el.value = value;

    el.style.position = 'absolute';
    el.style.left = '-9999px';
    el.readOnly = true; // avoid iOs keyboard opening
    el.contentEditable = 'true';

    document.body.appendChild(el);

    selectText(el, 0, value.length);

    document.execCommand('copy');
    document.body.removeChild(el);

};

export { copyToClipboard };

f
fujifish

Safari 13.1 中添加了剪贴板 API,请参见此处https://webkit.org/blog/10247/new-webkit-features-in-safari-13-1/

现在就像 navigator.clipboard.writeText("Text to copy") 一样简单


K
Khaled Elgendy

这对我来说适用于只读输入元素。

copyText = input => {
    const isIOSDevice = navigator.userAgent.match(/ipad|iphone/i);

    if (isIOSDevice) {
        input.setSelectionRange(0, input.value.length);
    } else {
        input.select();
    }

    document.execCommand('copy');
};

条件不是必需的,只需在 input.select 之后执行 input.setSelectionRange(0, input.value.length),因为它不会造成伤害
M
Mihey Mik

我的 ios 和其他浏览器在 ios 上测试后复制到剪贴板的功能:5c,6,7

/**
 * Copies to Clipboard value
 * @param {String} valueForClipboard value to be copied
 * @param {Boolean} isIOS is current browser is Ios (Mobile Safari)
 * @return {boolean} shows if copy has been successful
 */
const copyToClipboard = (valueForClipboard, isIOS) => {
    const textArea = document.createElement('textarea');
    textArea.value = valueForClipboard;

    textArea.style.position = 'absolute';
    textArea.style.left = '-9999px'; // to make it invisible and out of the reach
    textArea.setAttribute('readonly', ''); // without it, the native keyboard will pop up (so we show it is only for reading)

    document.body.appendChild(textArea);

    if (isIOS) {
        const range = document.createRange();
        range.selectNodeContents(textArea);

        const selection = window.getSelection();
        selection.removeAllRanges(); // remove previously selected ranges
        selection.addRange(range);
        textArea.setSelectionRange(0, valueForClipboard.length); // this line makes the selection in iOS
    } else {
        textArea.select(); // this line is for all other browsers except ios
    }

    try {
        return document.execCommand('copy'); // if copy is successful, function returns true
    } catch (e) {
        return false; // return false to show that copy unsuccessful
    } finally {
        document.body.removeChild(textArea); // delete textarea from DOM
    }
};

以上关于 contenteditable=true 的回答。我认为只属于div。而对于 <textarea> 不适用。

isIOS 变量可以检查为

const isIOS = navigator.userAgent.match(/ipad|ipod|iphone/i);


这个解决方案最适合我:适用于 safari 桌面和 safari mobile (iOS)。此外,我更喜欢该界面,因为我不必选择输入/文本区域字段,而只需通过传递参数来提供文本。
C
Cymro

这通过允许将文本作为变量传递来改进 Marco 的答案。这适用于 ios > 10。这在 Windows 上不起作用。

function CopyToClipboardIOS(TheText) {
  var el=document.createElement('input');
  el.setAttribute('style','position:absolute;top:-9999px');
  el.value=TheText;
  document.body.appendChild(el);
  var 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);
  document.execCommand('copy');
  el.remove();
}

Q
Quan Wu
<input id="copyIos" type="hidden" value="">
var clipboard = new Clipboard('.copyUrl');
                //兼容ios复制
                $('.copyUrl').on('click',function() {
                    var $input = $('#copyIos');
                    $input.val(share_url);
                    if (navigator.userAgent.match(/ipad|ipod|iphone/i)) {
                        clipboard.on('success', function(e) {
                            e.clearSelection();
                            $.sDialog({
                                skin: "red",
                                content: 'copy success!',
                                okBtn: false,
                                cancelBtn: false,
                                lock: true
                            });
                            console.log('copy success!');
                        });
                    } else {
                        $input.select();
                    }
                    //document.execCommand('copy');
                    $input.blur();
                });