Pregunta ¿Cómo copio al portapapeles en JavaScript?


¿Cuál es la mejor manera de copiar texto en el portapapeles? (multi-navegador)

Yo he tratado:

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

pero en Internet Explorer da un error de sintaxis. En Firefox, dice unsafeWindow is not defined.

Un buen truco sin flash: ¿Cómo accede Trello al portapapeles del usuario?


2663
2017-12-30 13:09


origen


Respuestas:


Visión de conjunto

Hay 3 API de navegador principales para copiar en el portapapeles:

  1. Async Clipboard API  [navigator.clipboard.writeText]
    • Porción centrada en texto disponible en Chrome 66 (marzo de 2018)
    • El acceso es asincrónico y utiliza Promesas de JavaScript, puede escribirse para que las solicitudes del usuario de seguridad (si se muestran) no interrumpan el JavaScript en la página.
    • El texto se puede copiar al portapapeles directamente desde una variable.
    • Solo se admite en páginas servidas a través de HTTPS.
    • En Chrome 66 páginas en pestañas activas pueden escribir en el portapapeles sin un aviso de permisos.
  2. document.execCommand('copy')
    • La mayoría de los navegadores admiten esto a partir de ~ abril de 2015 (ver Soporte del navegador a continuación).
    • El acceso es síncrono, es decir, detiene el JavaScript en la página hasta que se complete, incluida la visualización y la interacción del usuario con las indicaciones de seguridad.
    • El texto se lee del DOM y se coloca en el portapapeles.
    • Durante las pruebas ~ abril de 2015, solo se observó que Internet Explorer mostraba solicitudes de permisos mientras escribía en el portapapeles.
  3. Anulando el evento de copia
    • Consulte la documentación de la API del portapapeles en Anulando el evento de copia.
    • Le permite modificar lo que aparece en el portapapeles de cualquier evento de copia, puede incluir otros formatos de datos que no sean texto sin formato.
    • No se cubre aquí porque no responde directamente la pregunta.

Notas generales de desarrollo

No espere que los comandos relacionados con el portapapeles funcionen mientras prueba el código en la consola. En general, se requiere que la página esté activa (Async Clipboard API) o que requiera la interacción del usuario (por ejemplo, un clic del usuario) para permitir (document.execCommand('copy')) para acceder al portapapeles, ver más abajo para más detalles.

Async + Fallback

Debido al nivel de compatibilidad del navegador para la nueva API del portapapeles Async, es probable que desee recurrir a la document.execCommand('copy') método para obtener una buena cobertura del navegador.

Aquí hay un ejemplo 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>

Tenga en cuenta que este fragmento no funciona bien en la vista previa integrada de StackOverflow; puede intentarlo aquí: https://codepen.io/DeanMarkTaylor/pen/RMRaJX?editors=1011

Async Clipboard API

Tenga en cuenta que existe la posibilidad de "solicitar permiso" y probar el acceso al portapapeles a través de la API de permisos en 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 ('copia')

El resto de esta publicación entra en los matices y detalles de la document.execCommand('copy') API.

Soporte del navegador

El JavaScript document.execCommand('copy') la asistencia ha crecido, consulte los enlaces a continuación para las actualizaciones del navegador:

Ejemplo 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>

Ejemplo complejo: Copiar al portapapeles sin mostrar la entrada

El ejemplo simple anterior funciona muy bien si hay un textarea o input elemento visible en la pantalla.

En algunos casos, es posible que desee copiar texto en el portapapeles sin mostrar un input / textarea elemento. Este es un ejemplo de una forma de evitar esto (básicamente insertar elemento, copiar al portapapeles, eliminar elemento):

Probado con Google Chrome 44, Firefox 42.0a1 e 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>

Notas adicionales

Solo funciona si el usuario toma una acción

Todas document.execCommand('copy') las llamadas deben tener lugar como resultado directo de una acción del usuario, p. haga clic en controlador de eventos. Esta es una medida para evitar problemas con el portapapeles de los usuarios cuando no lo esperan.

Ver el Google Developers publica aquí para más información.

API del portapapeles

Tenga en cuenta que la especificación del borrador completo de la API del Portapapeles se puede encontrar aquí: https://w3c.github.io/clipboard-apis/

¿Es compatible?

  • document.queryCommandSupported('copy') debería regresar true si el comando "es compatible con el navegador".
  • y document.queryCommandEnabled('copy') regreso true Si el document.execCommand('copy') tendrá éxito si se llama ahora. Comprobando para asegurar que el comando fue llamado desde un hilo iniciado por el usuario y se cumplen otros requisitos.

Sin embargo, como ejemplo de problemas de compatibilidad del navegador, solo devolvió Google Chrome de ~ abril a ~ octubre de 2015 true de document.queryCommandSupported('copy') si el comando fue llamado desde un hilo iniciado por el usuario.

Tenga en cuenta los detalles de compatibilidad a continuación.

Detalle de compatibilidad del navegador

Mientras que una simple llamada a document.execCommand('copy') envuelto en una try/catch bloque llamado como resultado de un clic de usuario obtendrá la mayor compatibilidad uso el siguiente tiene algunas condiciones:

Cualquier llamada a document.execCommand, document.queryCommandSupported o document.queryCommandEnabled debe ser envuelto en una try/catch bloquear.

Diferentes implementaciones de navegador y versiones de navegador lanzan diferentes tipos de excepciones cuando se llaman en lugar de regresar false.

Las diferentes implementaciones de navegador todavía están en flujo y el API del portapapeles todavía está en borrador, así que recuerde hacer su prueba.


1581
2018-06-12 18:56



La copia automática al portapapeles puede ser peligrosa, por lo tanto, la mayoría de los navegadores (excepto IE) lo hacen muy difícil. Personalmente, utilizo el siguiente truco simple:

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

Al usuario se le presenta el cuadro de diálogo donde el texto que se va a copiar ya está seleccionado. Ahora es suficiente presionar Ctrl+do y Entrar (para cerrar la caja) - ¡y listo!

Ahora la operación de copia del portapapeles es SEGURA, porque el usuario lo hace de forma manual (pero de una manera bastante directa). Por supuesto, funciona en todos los navegadores.

<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



El siguiente enfoque funciona en Chrome, Firefox, Internet Explorer y Edge, y en versiones recientes de Safari (se agregó el soporte de Copia en la versión 10, que se lanzó en octubre de 2016).

  • Cree un área de texto y establezca su contenido en el texto que desea copiar al portapapeles.
  • Agregue el área de texto al DOM.
  • Seleccione el texto en el área de texto.
  • Llamar a document.execCommand ("copiar")
  • Retire el área de texto de la dom.

Nota: no verá el área de texto, ya que se agrega y elimina dentro de la misma invocación síncrona de código JavaScript.

Algunas cosas que debes tener en cuenta si lo estás implementando tú mismo:

  • Por razones de seguridad, esto solo puede invocarse desde un controlador de eventos como, por ejemplo, hacer clic (igual que con la ventana de apertura).
  • IE mostrará un diálogo de permisos la primera vez que se actualice el portapapeles.
  • IE, y Edge se desplazará cuando el área de texto esté enfocado.
  • execCommand () puede lanzar en algunos casos.
  • Las líneas nuevas y las pestañas se pueden tragar a menos que use un área de texto. (La mayoría de los artículos parecen recomendar el uso de un div)
  • El área de texto estará visible mientras se muestra el cuadro de diálogo de IE, o bien debe ocultarlo o utilizar la api de ClipboardData específica de IE.
  • En IE, los administradores del sistema pueden desactivar la API del portapapeles.

La siguiente función debe manejar todos los siguientes problemas lo más limpiamente posible. Por favor, deje un comentario si encuentra algún problema o tiene alguna sugerencia para mejorarlo.

// 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 desea una solución realmente simple (tarda menos de 5 minutos en integrarse) y se ve bien desde el primer momento, Clippy es una buena alternativa a algunas de las soluciones más complejas.

Clippy

Fue escrito por un cofundador de Github. Ejemplo de código de inserción de Flash a continuación:

<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>

Recuerde reemplazar #{text} con el texto que necesita copiado, y #{bgcolor} con un color


93
2017-10-17 14:40



Leer y modificar el portapapeles desde una página web plantea problemas de seguridad y privacidad. Sin embargo, en Internet Explorer, es posible hacerlo. encontré esto fragmento de ejemplo:

    <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



Recientemente escribí un publicación técnica del blog sobre este mismo problema (trabajo en Lucidchart y recientemente hicimos una revisión en nuestro portapapeles).

Copiar texto sin formato al portapapeles es relativamente simple, suponiendo que desea hacerlo durante un evento de copia del sistema (el usuario presiona Ctrldo o usa el menú del navegador).

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

Poner texto en el portapapeles no durante un evento de copia del sistema es mucho más difícil. Parece que algunas de estas otras respuestas hacen referencia a formas de hacerlo a través de Flash, que es la única forma de navegador cruzada para hacerlo (por lo que yo entiendo).

Aparte de eso, hay algunas opciones basadas en navegador por navegador.

Este es el más simple en IE, donde puede acceder al objeto clipboardData en cualquier momento desde JavaScript a través de:

window.clipboardData

(Sin embargo, cuando intente hacer esto fuera de un evento de corte, copia o pegado del sistema, IE le indicará al usuario que conceda permiso al portapapeles de la aplicación web).

En Chrome, puedes crear una extensión de Chrome que te dará permisos del portapapeles (Esto es lo que hacemos para Lucidchart). Luego, para los usuarios con su extensión instalada, solo tendrá que iniciar el evento del sistema usted mismo:

document.execCommand('copy');

Parece que Firefox tiene algunas opciones que permiten a los usuarios otorgar permisos a ciertos sitios para acceder al portapapeles, pero no he probado ninguno personalmente.


65
2017-12-03 20:31



clipboard.js es una utilidad pequeña, no flash, que permite copiar texto o datos html al portapapeles. Es muy fácil de usar, solo incluye .js y usa algo como esto:

<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 también está en GitHub


44
2017-08-11 15:33



ZeroClipboard es la mejor solución de navegador múltiple que he encontrado:

<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 necesita soporte no flash para iOS, simplemente agregue un respaldo:

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