J'utilise cette fonction pour copier une URL dans le presse-papier:
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 correctement sur les navigateurs de bureau, mais pas sur les appareils iOS, où ma fonction est correctement rendue, mais les données ne sont pas copiées du tout dans le Presse-papiers. Qu'est-ce qui cause cela et comment pourrais-je résoudre ce problème?
On dirait qu'avec l'aide de plages de sélection et de quelques modifications, il est possible de copier directement dans le presse-papiers sur Safari iOS (> = 10). J'ai personnellement testé cela sur iPhone 5C iOS 10.3.3 et iPhone 8 iOS 11.1. Cependant, il semble y avoir certaines restrictions, qui sont:
<input>
et <textarea>
.<form>
, il doit alors être contenteditable
.readonly
(bien que vous puissiez essayer, ce n'est pas une méthode "officielle" documentée nulle part).Pour couvrir ces quatre "exigences", vous devrez:
<input>
ou <textarea>
.contenteditable
et readonly
de l'élément pour pouvoir les restaurer après la copie.contenteditable
par true
et readonly
par false
.contenteditable
et readonly
précédentes.execCommand('copy')
.Cela entraînera le déplacement du curseur de l'appareil de l'utilisateur, la sélection de tout le texte de l'élément souhaité, puis l'envoi automatique de la commande de copie. L'utilisateur verra le texte sélectionné et l'info-bulle avec les options sélectionner/copier/coller s'affichera.
Maintenant, cela semble un peu compliqué et trop fastidieux de simplement émettre une commande de copie, donc je ne suis pas sûr que ce soit un choix de conception par Apple, mais qui sait ... dans le même temps, ceci fonctionne actuellement sur iOS> = 10 .
Cela dit, des polyfillages tels que celui-ci pourraient être utilisés pour simplifier cette action et la rendre compatible entre les navigateurs (merci @ Toskan pour le lien dans les commentaires).
Exemple de travail
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>
.
Sur iOS <10 , il existe des restrictions pour Safari (qui sont en fait des mesures de sécurité) à API Clipboard :
copy
uniquement sur une sélection valide et cut
et paste
uniquement dans des champs modifiables ciblés.document.execCommand()
. Notez que "clé de raccourci" signifie certains éléments cliquables (par ex./action menu coller ou raccourci clavier personnalisé iOS) ou une touche physique (par exemple, un clavier Bluetooth connecté).ClipboardEvent
.Donc (au moins à partir de maintenant) , il n'est pas possible de copier par programme un texte/une valeur dans le presse-papiers sur un périphérique iOS à l'aide de Javascript . Seul l'utilisateur peut décider de copier ou non quelque chose.
Il est toutefois possible de sélectionner quelque chose par programme , de sorte que l'utilisateur ne doit appuyer que sur l'info-bulle "Copier" indiquée dans la sélection. Ceci peut être réalisé avec exactement le même code que ci-dessus, en enlevant simplement la execCommand('copy')
, qui ne fonctionnera en effet pas.
J'ai cherché des solutions et j'en ai trouvé une qui fonctionne réellement: http://www.seabreezecomputers.com/tips/copy2clipboard.htm
Fondamentalement, l'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();
Pour des raisons de sécurité, iOS Safari n'autorise que document.execCommand('copy')
pour le texte contenu dans un conteneur contentEditable
.
La solution de contournement consiste à détecter iOS Safari et à basculer rapidement contentEditable
avant d'exécuter document.execCommand('copy')
.
La fonction suivante devrait fonctionner dans tous les navigateurs/appareils et accepter 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>
Ceci est mon implémentation cross-navigateur
Vous pouvez le tester en exécutant l'extrait ci-dessous
Exemple:
copyToClipboard("Hello World");
/**
* Copy a string to clipboard
* @param {String} string The string to be copied to clipboard
* @return {Boolean} returns a boolean correspondent to the success of the copy operation.
*/
function copyToClipboard(string) {
let textarea;
let result;
try {
textarea = document.createElement('textarea');
textarea.setAttribute('readonly', true);
textarea.setAttribute('contenteditable', true);
textarea.style.position = 'fixed'; // prevent scroll from jumping to the bottom when focus is set.
textarea.value = string;
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
const range = document.createRange();
range.selectNodeContents(textarea);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
textarea.setSelectionRange(0, textarea.value.length);
result = document.execCommand('copy');
} catch (err) {
console.error(err);
result = null;
} finally {
document.body.removeChild(textarea);
}
// manual copy fallback using Prompt
if (!result) {
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
const copyHotkey = isMac ? '⌘C' : 'CTRL+C';
result = Prompt(`Press ${copyHotkey}`, string); // eslint-disable-line no-alert
if (!result) {
return false;
}
}
return true;
}
Demo: <button onclick="copyToClipboard('It works!\nYou can upvote my answer now :)') ? this.innerText='Copied!': this.innerText='Sorry :(' ">Click here</button>
<p>
<textarea placeholder="(Testing area) Paste here..." cols="80" rows="4"></textarea>
</p>
NOTE: Cela ne fonctionne pas s'il n'est pas initié par l'utilisateur, comme un délai d'attente ou un événement asynchrone!
Il doit provenir d'un événement de confiance, comme appelé d'un événement
click
sur un bouton.
S'il vous plaît vérifier ma solution.
Cela 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/64781c6a1329b48a455b645d361a9aahttps://fiddle.jshell.net/k9ejqmqt/1/
J'espère que ça vous aide.
Cordialement.
Ma solution a été créée en combinant d'autres réponses de cette page.
Contrairement aux autres réponses, cela ne nécessite pas que vous ayez déjà un élément sur la page. Il créera sa propre zone de texte et nettoiera le désordre par la suite.
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);
}
Bien, voici le refactor TypeScript ci-dessus au cas où quelqu'un serait intéressé (écrit en tant que module 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 };
Ma fonction pour les navigateurs ios et autres copiant vers le presse-papiers après avoir été testée sur 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
}
};
ci-dessus la réponse à propos de contenteditable = true. Je pense que n'appartient qu'aux divs. Et pour <textarea>
n'est pas applicable.
la variable isIOS peut être cochée
const isIOS = navigator.userAgent.match(/ipad|iPod|iphone/i);
Celui-ci a fonctionné pour moi pour un élément d'entrée en lecture seule.
copyText = input => {
const isIOSDevice = navigator.userAgent.match(/ipad|iphone/i);
if (isIOSDevice) {
input.setSelectionRange(0, input.value.length);
} else {
input.select();
}
document.execCommand('copy');
};