Question Comment copier dans le presse-papiers en JavaScript?


Quel est le meilleur moyen de copier du texte dans le presse-papiers? (multi-navigateur)

J'ai essayé:

function copyToClipboard(text) {
    if (window.clipboardData) { // Internet Explorer
        window.clipboardData.setData("Text", text);
    } else {  
        unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  
        const clipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper);  
        clipboardHelper.copyString(text);
    }
}

mais dans Internet Explorer, il donne une erreur de syntaxe. Dans Firefox, il est dit unsafeWindow is not defined.

Une belle astuce sans flash: Comment Trello accède-t-il au presse-papiers de l'utilisateur?


2663
2017-12-30 13:09


origine


Réponses:


Aperçu

Il existe trois API de navigateur principales pour la copie dans le Presse-papiers:

  1. API du presse-papiers asynchrone  [navigator.clipboard.writeText]
    • Partie axée sur le texte disponible dans Chrome 66 (mars 2018)
    • L'accès est asynchrone et utilise Promesses JavaScript, peut être écrit pour que les invites de l'utilisateur de sécurité (si affichées) n'interrompent pas le JavaScript dans la page.
    • Le texte peut être copié directement dans le presse-papiers à partir d'une variable.
    • Uniquement pris en charge sur les pages servies via HTTPS.
    • Dans Chrome 66 pages dans les onglets actifs peuvent écrire dans le Presse-papiers sans une invite d'autorisation.
  2. document.execCommand('copy')
    • La plupart des navigateurs prennent en charge cette fonctionnalité à partir du mois d'avril 2015 (voir le support du navigateur ci-dessous).
    • L'accès est synchrone, c'est-à-dire qu'il arrête JavaScript dans la page jusqu'à ce qu'il soit complet, y compris l'affichage et l'interaction de l'utilisateur avec les invites de sécurité.
    • Le texte est lu depuis le DOM et placé dans le presse-papiers.
    • Pendant le test ~ Avril 2015, seul Internet Explorer a été noté comme affichant les demandes d'autorisation lors de l'écriture dans le presse-papiers.
  3. Remplacer l'événement de copie
    • Voir la documentation de l'API du Presse-papiers sur Remplacer l'événement de copie.
    • Vous permet de modifier ce qui apparaît dans le presse-papiers à partir de n'importe quel événement de copie, peut inclure d'autres formats de données autres que du texte brut.
    • Non couvert ici car il ne répond pas directement à la question.

Notes générales de développement

Ne vous attendez pas à ce que les commandes liées au Presse-papiers fonctionnent pendant que vous testez le code dans la console. Généralement, la page doit être active (API Presse-papiers asynchrone) ou nécessite une interaction de l'utilisateur (par exemple, un clic de l'utilisateur) pour autoriser (document.execCommand('copy')) pour accéder au presse-papiers, voir ci-dessous pour plus de détails.

Async + Fallback

En raison du niveau de support du navigateur pour la nouvelle API du Presse-papiers Async, vous voudrez probablement vous replier document.execCommand('copy') méthode pour obtenir une bonne couverture de navigateur.

Voici un exemple simple:

function fallbackCopyTextToClipboard(text) {
  var textArea = document.createElement("textarea");
  textArea.value = text;
  document.body.appendChild(textArea);
  textArea.focus();
  textArea.select();

  try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Fallback: Copying text command was ' + msg);
  } catch (err) {
    console.error('Fallback: Oops, unable to copy', err);
  }

  document.body.removeChild(textArea);
}
function copyTextToClipboard(text) {
  if (!navigator.clipboard) {
    fallbackCopyTextToClipboard(text);
    return;
  }
  navigator.clipboard.writeText(text).then(function() {
    console.log('Async: Copying to clipboard was successful!');
  }, function(err) {
    console.error('Async: Could not copy text: ', err);
  });
}

var copyBobBtn = document.querySelector('.js-copy-bob-btn'),
  copyJaneBtn = document.querySelector('.js-copy-jane-btn');

copyBobBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Bob');
});


copyJaneBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Jane');
});
<div style="display:inline-block; vertical-align:top;">
  <button class="js-copy-bob-btn">Set clipboard to BOB</button><br /><br />
  <button class="js-copy-jane-btn">Set clipboard to JANE</button>
</div>
<div style="display:inline-block;">
  <textarea class="js-test-textarea" cols="35" rows="4">Try pasting into here to see what you have on your clipboard:
  
  </textarea>
</div>

Notez que cet extrait ne fonctionne pas correctement dans l'aperçu intégré de StackOverflow. Vous pouvez l'essayer ici: https://codepen.io/DeanMarkTaylor/pen/RMRaJX?editors=1011

API du presse-papiers asynchrone

Notez qu'il est possible de "demander l'autorisation" et de tester l'accès au Presse-papiers via l'API des autorisations dans Chrome 66.

var text = "Example text to appear on clipboard";
navigator.clipboard.writeText(text).then(function() {
  console.log('Async: Copying to clipboard was successful!');
}, function(err) {
  console.error('Async: Could not copy text: ', err);
});

document.execCommand ('copy')

Le reste de ce post va dans les nuances et les détails de la document.execCommand('copy') API

Support du navigateur

Le JavaScript document.execCommand('copy') le support a augmenté, voir les liens ci-dessous pour les mises à jour du navigateur:

Exemple simple

var copyTextareaBtn = document.querySelector('.js-textareacopybtn');

copyTextareaBtn.addEventListener('click', function(event) {
  var copyTextarea = document.querySelector('.js-copytextarea');
  copyTextarea.focus();
  copyTextarea.select();

  try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copying text command was ' + msg);
  } catch (err) {
    console.log('Oops, unable to copy');
  }
});
<p>
  <button class="js-textareacopybtn" style="vertical-align:top;">Copy Textarea</button>
  <textarea class="js-copytextarea">Hello I'm some text</textarea>
</p>

Exemple complexe: Copier dans le presse-papier sans afficher d'entrée

L'exemple simple ci-dessus fonctionne très bien s'il y a un textarea ou input élément visible à l'écran.

Dans certains cas, vous pouvez copier du texte dans le presse-papiers sans afficher input / textarea élément. Voici un exemple d'une façon de contourner ce problème (en gros, insérez l'élément, copiez dans le presse-papier, supprimez l'élément):

Testé avec Google Chrome 44, Firefox 42.0a1 et IE 11.0.8600.17814.

function copyTextToClipboard(text) {
  var textArea = document.createElement("textarea");

  //
  // *** This styling is an extra step which is likely not required. ***
  //
  // Why is it here? To ensure:
  // 1. the element is able to have focus and selection.
  // 2. if element was to flash render it has minimal visual impact.
  // 3. less flakyness with selection and copying which **might** occur if
  //    the textarea element is not visible.
  //
  // The likelihood is the element won't even render, not even a flash,
  // so some of these are just precautions. However in IE the element
  // is visible whilst the popup box asking the user for permission for
  // the web page to copy to the clipboard.
  //

  // Place in top-left corner of screen regardless of scroll position.
  textArea.style.position = 'fixed';
  textArea.style.top = 0;
  textArea.style.left = 0;

  // Ensure it has a small width and height. Setting to 1px / 1em
  // doesn't work as this gives a negative w/h on some browsers.
  textArea.style.width = '2em';
  textArea.style.height = '2em';

  // We don't need padding, reducing the size if it does flash render.
  textArea.style.padding = 0;

  // Clean up any borders.
  textArea.style.border = 'none';
  textArea.style.outline = 'none';
  textArea.style.boxShadow = 'none';

  // Avoid flash of white box if rendered for any reason.
  textArea.style.background = 'transparent';


  textArea.value = text;

  document.body.appendChild(textArea);
  textArea.focus();
  textArea.select();

  try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copying text command was ' + msg);
  } catch (err) {
    console.log('Oops, unable to copy');
  }

  document.body.removeChild(textArea);
}


var copyBobBtn = document.querySelector('.js-copy-bob-btn'),
  copyJaneBtn = document.querySelector('.js-copy-jane-btn');

copyBobBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Bob');
});


copyJaneBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Jane');
});
<div style="display:inline-block; vertical-align:top;">
  <button class="js-copy-bob-btn">Set clipboard to BOB</button><br /><br />
  <button class="js-copy-jane-btn">Set clipboard to JANE</button>
</div>
<div style="display:inline-block;">
  <textarea class="js-test-textarea" cols="35" rows="4">Try pasting into here to see what you have on your clipboard:
  
  </textarea>
</div>

Notes complémentaires

Ne fonctionne que si l'utilisateur prend une action

Tout document.execCommand('copy') les appels doivent avoir lieu en conséquence directe d'une action de l'utilisateur, par ex. cliquez sur le gestionnaire d'événements. Ceci est une mesure pour empêcher de jouer avec le presse-papiers des utilisateurs quand ils ne s'y attendent pas.

Voir le Les développeurs Google postent ici pour plus d'informations.

API du Presse-papiers

Notez que la spécification de brouillon complète de l'API du Presse-papiers peut être trouvée ici: https://w3c.github.io/clipboard-apis/

Est-ce supporté?

  • document.queryCommandSupported('copy') devrait revenir true si la commande "est supportée par le navigateur".
  • et document.queryCommandEnabled('copy') revenir true si la document.execCommand('copy') réussira s'il est appelé maintenant. Vérification pour s'assurer que la commande a été appelée à partir d'un thread initié par l'utilisateur et que d'autres conditions sont remplies.

Cependant, en tant qu'exemple de problèmes de compatibilité de navigateur, Google Chrome de ~ Avril à Octobre 2015 seulement retourné true de document.queryCommandSupported('copy') si la commande a été appelée à partir d'un thread initié par l'utilisateur.

Notez les détails de compatibilité ci-dessous.

Détails de compatibilité du navigateur

Alors qu'un simple appel à document.execCommand('copy') enveloppé dans un try/catch bloc appelé à la suite d'un clic de l'utilisateur vous obtiendrez le plus d'utilisation de compatibilité ce qui suit a quelques conditions:

Tout appel à document.execCommand, document.queryCommandSupported ou document.queryCommandEnabled devrait être enveloppé dans un try/catch bloc.

Différentes implémentations de navigateur et versions de navigateur lancent différents types d'exceptions lorsqu'elles sont appelées au lieu de renvoyer false.

Différentes implémentations de navigateurs sont toujours en cours et la API du Presse-papiers est toujours en brouillon, alors n'oubliez pas de faire vos tests.


1581
2018-06-12 18:56



La copie automatique vers le presse-papiers peut être dangereuse, donc la plupart des navigateurs (sauf IE) rendent la tâche très difficile. Personnellement, j'utilise l'astuce simple suivante:

function copyToClipboard(text) {
  window.prompt("Copy to clipboard: Ctrl+C, Enter", text);
}

L'utilisateur est présenté avec la boîte d'invite, où le texte à copier est déjà sélectionné. Maintenant, il suffit d'appuyer sur Ctrl+C et Entrer (pour fermer la boîte) - et voilà!

Maintenant, l'opération de copie de presse-papiers est sûre, parce que l'utilisateur le fait manuellement (mais d'une manière assez simple). Bien sûr, fonctionne dans tous les navigateurs.

<button id="demo" onclick="copyToClipboard(document.getElementById('demo').innerHTML)">This is what I want to copy</button>

<script>
  function copyToClipboard(text) {
    window.prompt("Copy to clipboard: Ctrl+C, Enter", text);
  }
</script>


1195
2018-05-19 08:06



L'approche suivante fonctionne dans Chrome, Firefox, Internet Explorer et Edge, et dans les versions récentes de Safari (le support de copie a été ajouté dans la version 10 qui a été publiée en octobre 2016).

  • Créez une zone de texte et définissez son contenu sur le texte que vous souhaitez copier dans le Presse-papiers.
  • Ajoutez la zone de texte au DOM.
  • Sélectionnez le texte dans la zone de texte.
  • Appelez document.execCommand ("copier")
  • Supprimez la zone de texte de la dom.

Note: vous ne verrez pas la zone de texte, car elle est ajoutée et supprimée dans la même invocation synchrone du code Javascript.

Certaines choses à surveiller si vous mettez en œuvre vous-même:

  • Pour des raisons de sécurité, cela ne peut être appelé qu'à partir d'un gestionnaire d'événements tel que click (Tout comme avec les fenêtres d'ouverture).
  • IE affiche une boîte de dialogue d'autorisation lors de la première mise à jour du Presse-papiers.
  • IE et Edge défilent lorsque la zone de texte est mise au point.
  • execCommand () peut lancer dans certains cas.
  • Les nouvelles lignes et les onglets peuvent être avalés sauf si vous utilisez une zone de texte. (La plupart des articles semblent recommander l'utilisation d'un div)
  • La zone de texte sera visible lorsque la boîte de dialogue IE est affichée, vous devez soit la masquer, soit utiliser l'API spécifique clipboardData IE.
  • Dans les administrateurs système IE peut désactiver l'API du Presse-papiers.

La fonction ci-dessous devrait traiter tous les problèmes suivants aussi proprement que possible. S'il vous plaît laisser un commentaire si vous trouvez des problèmes ou avez des suggestions pour l'améliorer.

// Copies a string to the clipboard. Must be called from within an 
// event handler such as click. May return false if it failed, but
// this is not always possible. Browser support for Chrome 43+, 
// Firefox 42+, Safari 10+, Edge and IE 10+.
// IE: The clipboard feature may be disabled by an administrator. By
// default a prompt is shown the first time the clipboard is 
// used (per session).
function copyToClipboard(text) {
    if (window.clipboardData && window.clipboardData.setData) {
        // IE specific code path to prevent textarea being shown while dialog is visible.
        return clipboardData.setData("Text", text); 

    } else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
        var textarea = document.createElement("textarea");
        textarea.textContent = text;
        textarea.style.position = "fixed";  // Prevent scrolling to bottom of page in MS Edge.
        document.body.appendChild(textarea);
        textarea.select();
        try {
            return document.execCommand("copy");  // Security exception may be thrown by some browsers.
        } catch (ex) {
            console.warn("Copy to clipboard failed.", ex);
            return false;
        } finally {
            document.body.removeChild(textarea);
        }
    }
}

https://jsfiddle.net/fx6a6n6x/


194
2017-11-26 00:03



Si vous voulez une solution vraiment simple (moins de 5 minutes à intégrer) et une bonne apparence dès la sortie de la boîte, alors Clippy est une bonne alternative à certaines des solutions les plus complexes.

Clippy

Il a été écrit par un co-fondateur de Github. Exemple de code d'intégration Flash ci-dessous:

<object 
   classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
   width="110"
   height="14"
   id="clippy">
  <param name="movie" value="/flash/clippy.swf"/>
  <param name="allowScriptAccess" value="always"/>
  <param name="quality" value="high"/>
  <param name="scale" value="noscale"/>
  <param NAME="FlashVars" value="text=#{text}"/>
  <param name="bgcolor" value="#{bgcolor}"/>
  <embed 
     src="/flash/clippy.swf"
     width="110"
     height="14"
     name="clippy"
     quality="high"
     allowScriptAccess="always"
     type="application/x-shockwave-flash"
     pluginspage="http://www.macromedia.com/go/getflashplayer"
     FlashVars="text=#{text}"
     bgcolor="#{bgcolor}"/>
</object>

N'oubliez pas de remplacer #{text} avec le texte dont vous avez besoin copié, et #{bgcolor} avec une couleur.


93
2017-10-17 14:40



La lecture et la modification du presse-papiers à partir d'une page Web soulève des problèmes de sécurité et de confidentialité. Cependant, dans Internet Explorer, il est possible de le faire. j'ai trouvé ça exemple d'extrait:

    <script type="text/javascript">
        function select_all(obj) {
            var text_val=eval(obj);
            text_val.focus();
            text_val.select();
            r = text_val.createTextRange();
            if (!r.execCommand) return; // feature detection
            r.execCommand('copy');
        }
    </script>
    <input value="http://www.sajithmr.com"
     onclick="select_all(this)" name="url" type="text" />


77
2017-12-30 13:33



J'ai récemment écrit un article de blog technique sur ce même problème (je travaille chez Lucidchart et nous avons récemment fait une révision sur notre presse-papiers).

La copie de texte brut dans le Presse-papiers est relativement simple, en supposant que vous souhaitiez le faire lors d'un événement de copie système (l'utilisateur appuie sur CtrlC ou utilise le menu du navigateur).

var isIe = (navigator.userAgent.toLowerCase().indexOf("msie") != -1 
           || navigator.userAgent.toLowerCase().indexOf("trident") != -1);

document.addEventListener('copy', function(e) {
    var textToPutOnClipboard = "This is some text";
    if (isIe) {
        window.clipboardData.setData('Text', textToPutOnClipboard);    
    } else {
        e.clipboardData.setData('text/plain', textToPutOnClipboard);
    }
    e.preventDefault();
});

Mettre du texte dans le presse-papiers pendant un événement de copie du système est beaucoup plus difficile. Il semble que certaines de ces autres réponses indiquent des façons de le faire via Flash, qui est la seule façon de le faire (pour autant que je sache).

À part cela, il y a quelques options sur une base de navigateur par navigateur.

C'est le plus simple dans IE, où vous pouvez accéder à l'objet clipboardData à tout moment à partir de JavaScript via:

window.clipboardData

(Lorsque vous tentez de le faire en dehors d'un système, coupez, copiez ou collez l'événement, cependant, IE demandera à l'utilisateur d'accorder l'autorisation du presse-papiers de l'application Web.)

Dans Chrome, vous pouvez créer une extension Chrome qui vous donnera autorisations de presse-papiers (c'est ce que nous faisons pour Lucidchart). Ensuite, pour les utilisateurs avec votre extension installée, vous devrez simplement déclencher l'événement système vous-même:

document.execCommand('copy');

Il semble que Firefox a quelques options qui permettent aux utilisateurs d'accorder des autorisations à certains sites pour accéder au presse-papiers, mais je n'en ai jamais essayé personnellement.


65
2017-12-03 20:31



clipboard.js est un petit utilitaire, non-flash, qui permet de copier du texte ou des données html dans le presse-papier. C'est très facile à utiliser, il suffit d'inclure le .js et d'utiliser quelque chose comme ceci:

<button id='markup-copy'>Copy Button</button>

<script>
document.getElementById('markup-copy').addEventListener('click', function() {
  clipboard.copy({
    'text/plain': 'Markup text. Paste me into a rich text editor.',
    'text/html': '<i>here</i> is some <b>rich text</b>'
  }).then(
    function(){console.log('success'); },
    function(err){console.log('failure', err);
  });

});
</script>

clipboard.js est aussi sur GitHub


44
2017-08-11 15:33



ZeroClipboard est la meilleure solution de navigateur que j'ai trouvée:

<div id="copy" data-clipboard-text="Copy Me!">Click to copy</div>    
<script src="ZeroClipboard.js"></script>
<script>
  var clip = new ZeroClipboard( document.getElementById('copy') );
</script>

Si vous avez besoin d'une prise en charge non-flash pour iOS, ajoutez simplement une option de repli:

clip.on( 'noflash', function ( client, args ) {
    $("#copy").click(function(){            
        var txt = $(this).attr('data-clipboard-text');
        prompt ("Copy link, then click OK.", txt);
    });
});  

http://zeroclipboard.org/

https://github.com/zeroclipboard/ZeroClipboard


35
2017-11-21 20:41



Voici ma prise sur celui-là ..

function copy(text) {
    var input = document.createElement('input');
    input.setAttribute('value', text);
    document.body.appendChild(input);
    input.select();
    var result = document.execCommand('copy');
    document.body.removeChild(input)
    return result;
 }

29
2017-09-14 09:20



D'un des projets sur lesquels j'ai travaillé, un plugin jQuery copy-to-clipboard qui utilise le Presse-papiers zéro bibliothèque.

Il est plus facile à utiliser que le plugin Zero Clipboard natif si vous êtes un utilisateur lourd de jQuery.


25
2018-05-03 22:17



J'ai trouvé la solution suivante:

Le gestionnaire de raccourci crée une étiquette "pré". Nous définissons le contenu à copier sur cette balise, puis effectuons une sélection sur cette balise et renvoyons true dans handler. Cela appelle le gestionnaire standard de chrome et copie le texte sélectionné.

Et si vous avez besoin, vous pouvez définir le délai d'attente pour la fonction de restauration de la sélection précédente. Mon implémentation sur Mootools:

   function EnybyClipboard() {
     this.saveSelection = false;
     this.callback = false;
     this.pastedText = false;

     this.restoreSelection = function() {
       if (this.saveSelection) {
         window.getSelection().removeAllRanges();
         for (var i = 0; i < this.saveSelection.length; i++) {
           window.getSelection().addRange(this.saveSelection[i]);
         }
         this.saveSelection = false;
       }
     };

     this.copyText = function(text) {
       var div = $('special_copy');
       if (!div) {
         div = new Element('pre', {
           'id': 'special_copy',
           'style': 'opacity: 0;position: absolute;top: -10000px;right: 0;'
         });
         div.injectInside(document.body);
       }
       div.set('text', text);
       if (document.createRange) {
         var rng = document.createRange();
         rng.selectNodeContents(div);
         this.saveSelection = [];
         var selection = window.getSelection();
         for (var i = 0; i < selection.rangeCount; i++) {
           this.saveSelection[i] = selection.getRangeAt(i);
         }
         window.getSelection().removeAllRanges();
         window.getSelection().addRange(rng);
         setTimeout(this.restoreSelection.bind(this), 100);
       } else return alert('Copy not work. :(');
     };

     this.getPastedText = function() {
       if (!this.pastedText) alert('Nothing to paste. :(');
       return this.pastedText;
     };

     this.pasteText = function(callback) {
       var div = $('special_paste');
       if (!div) {
         div = new Element('textarea', {
           'id': 'special_paste',
           'style': 'opacity: 0;position: absolute;top: -10000px;right: 0;'
         });
         div.injectInside(document.body);
         div.addEvent('keyup', function() {
           if (this.callback) {
             this.pastedText = $('special_paste').get('value');
             this.callback.call(null, this.pastedText);
             this.callback = false;
             this.pastedText = false;
             setTimeout(this.restoreSelection.bind(this), 100);
           }
         }.bind(this));
       }
       div.set('value', '');
       if (document.createRange) {
         var rng = document.createRange();
         rng.selectNodeContents(div);
         this.saveSelection = [];
         var selection = window.getSelection();
         for (var i = 0; i < selection.rangeCount; i++) {
           this.saveSelection[i] = selection.getRangeAt(i);
         }
         window.getSelection().removeAllRanges();
         window.getSelection().addRange(rng);
         div.focus();
         this.callback = callback;
       } else return alert('Fail to paste. :(');
     };
   }

Usage:

enyby_clip = new EnybyClipboard(); //init 

enyby_clip.copyText('some_text'); // place this in CTRL+C handler and return true;

enyby_clip.pasteText(function callback(pasted_text) {
        alert(pasted_text);
}); // place this in CTRL+V handler and return true;

En cas de collage, il crée une zone de texte et fonctionne de la même manière.

PS peut être cette solution peut être utilisée pour créer une solution de navigateur complet sans flash. Ses œuvres en FF et Chrome.


21
2017-07-05 15:33