Copie au bloc-notes en utilisant Javascript dans iOS

j'utilise cette fonction pour copier une URL vers le presse-papiers:

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

Tout fonctionne bien sur les navigateurs de bureau, mais pas sur les appareils iOS, où ma fonction retourne avec succès, mais les données ne sont pas du tout copiées dans le presse-papiers. Quelle est la cause et comment pourrais-je résoudre ce problème?

36
demandé sur Polsonby 2015-12-02 17:54:22

5 réponses

mise à jour! iOS > = 10

ressemble avec l'aide des gammes de sélection et un peu de hack il est possible de copier directement au presse-papiers sur iOS (>= 10) Safari. J'ai personnellement testé sur iPhone 5C iOS 10.3.3 et iPhone 8 iOS 11.1. Cependant, il semble y avoir certaines restrictions, qui sont:

  1. le texte ne peut être copié qu'à partir des éléments <input> et <textarea> .
  2. si l'élément le texte est pas à l'intérieur d'un <form> , alors il doit être contenteditable .
  3. l'élément contenant le texte doit et non être readonly (bien que vous puissiez essayer, ce n'est pas une méthode" officielle " documentée n'importe où).
  4. Le texte à l'intérieur de l'élément doit être dans la plage de sélection.

pour couvrir ces quatre "exigences", vous devrez::

  1. placez le texte à copier dans un élément <input> ou <textarea> .
  2. sauvegarder les anciennes valeurs de contenteditable et readonly de l'élément pour pouvoir les restaurer après copie.
  3. changer contenteditable en true et readonly en false .
  4. Créer un gamme pour sélectionner l'élément souhaité et l'ajouter à la fenêtre sélection.
  5. définit la gamme de sélection" 1519600920 pour l'ensemble de l'élément.
  6. restaurer les valeurs précédentes contenteditable et readonly .
  7. Exécuter execCommand('copy') .

cela provoquera le caret de l'appareil de l'utilisateur de se déplacer et de sélectionner tout le texte dans l'élément que vous voulez, puis automatiquement émettre la commande de copie. De l'utilisateur le texte sélectionné et le outil de pointe avec les options sélectionner/copier/coller sera montré.

maintenant, cela semble un peu compliqué et trop de tracas pour juste émettre une commande de copie, donc je ne suis pas sûr que ce soit un choix de conception prévu par Apple, mais qui sait... entre - temps, ce fonctionne actuellement sur iOS >= 10 .

avec ceci dit, les polyfills comme celui-ci pourrait être utilisé pour simplifier cette action et faire croix-navigateur compatible (merci @Toskan pour le lien dans les commentaires).

exemple pratique

pour résumer, le code dont vous aurez besoin ressemble à ceci:

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

notez que le paramètre el de cette fonction doit être un <input> ou un <textarea> .

ancienne réponse: versions précédentes de iOS

sur iOS < 10 il y a quelques restrictions pour Safari (qui sont en réalité des mesures de sécurité), à la presse-papiers de l'API :

  • feux copy événements uniquement sur une sélection valide et cut et paste seulement des champs modifiables.
  • it only supports OS presse-papiers lecture/écriture via les touches de raccourci, et non par document.execCommand() . noter que par "touche de raccourci", on entend une touche cliquable (par exemple, menu d'action copier/coller ou raccourci clavier iOS personnalisé) ou physique (par exemple, clavier bluetooth connecté).
  • il ne supporte pas le constructeur ClipboardEvent .

donc (au moins à partir de maintenant) il n'est pas possible de copier programmatiquement du texte ou de la valeur dans le presse-papiers sur un périphérique iOS en utilisant Javascript . Seul l'utilisateur peut décider de copier quelque chose.

il est cependant possible de sélectionner quelque chose par programme , de sorte que l'utilisateur n'a qu'à cliquer sur le bout d'outil "Copier" affiché sur la sélection. Cela peut être réalisé avec le même code que ci-dessus, en enlevant simplement le execCommand('copy') , qui ne va pas fonctionner.

73
répondu Marco Bonelli 2018-09-01 12:38:46

j'ai cherché des solutions et j'en ai trouvé une qui fonctionne vraiment: http://www.seabreezecomputers.com/tips/copy2clipboard.htm

en gros, exemple pourrait être quelque chose comme:

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();
36
répondu Marko Milojevic 2016-12-21 16:27:47

pour des raisons de sécurité, iOS Safari n'autorise document.execCommand('copy') que pour le texte à l'intérieur d'un conteneur contentEditable .

la solution est de détecter iOS Safari et de basculer rapidement contentEditable avant d'exécuter document.execCommand('copy') .

la fonction suivante doit fonctionner dans tous les navigateurs / dispositifs et accepte un sélecteur CSS ou 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; }
<input class="important-message" type="text" value="Hello World" />
<button onclick="copyToClipboard('.important-message')">Copy</button>
10
répondu John Doherty 2017-11-09 16:52:59

Vérifiez ma solution.

il fonctionne sur Safari (testé sur iPhone 7 et iPad) et sur d'autres navigateurs.

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 /

Espère que vous aide.

Cordialement.

6
répondu Rodrigo 2017-10-23 11:34:59
<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();
                });
-1
répondu Quan Wu 2017-08-31 03:11:58