Development Tip

iOS에서 자바 스크립트를 사용하여 클립 보드에 복사

yourdevel 2020. 11. 12. 20:27
반응형

iOS에서 자바 스크립트를 사용하여 클립 보드에 복사


이 함수를 사용하여 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 장치에서는 작동하지 않지만 데이터는 클립 보드에 전혀 복사되지 않습니다. 이 문제의 원인은 무엇이며 어떻게이 문제를 해결할 수 있습니까?


최신 정보! iOS> = 10

선택 범위와 약간의 해킹 덕분에 iOS (> = 10) Safari의 클립 보드에 직접 복사 할 수 있습니다. 개인적으로 iPhone 5C iOS 10.3.3 및 iPhone 8 iOS 11.1에서 테스트했습니다. 그러나 다음과 같은 몇 가지 제한 사항이있는 것 같습니다.

  1. 텍스트는 <input><textarea>요소 에서만 복사 할 수 있습니다 .
  2. 텍스트를 포함하는 요소가 내부에 없으면<form> 이어야합니다 contenteditable.
  3. 텍스트를 담고있는 요소는 절대로 안됩니다 readonly(시도 할 수 있지만 이것은 문서화 된 "공식"방법이 아닙니다).
  4. 요소 내부의 텍스트는 선택 범위에 있어야합니다.

이러한 네 가지 "요구 사항"을 모두 충족하려면 다음을 수행해야합니다.

  1. <input>또는 <textarea>요소 안에 복사 할 텍스트를 넣으십시오 .
  2. 복사 후 복원 할 수 있도록 contenteditablereadonly요소 의 이전 값을 저장하십시오 .
  3. 변경 contenteditabletruereadonlyfalse.
  4. 원하는 요소를 선택하고 창의 선택에 추가 할 범위만듭니다 .
  5. 전체 요소 선택 범위설정합니다 .
  6. 이전 contenteditablereadonly값을 복원하십시오 .
  7. 을 실행 execCommand('copy')합니다.

이렇게하면 사용자 장치의 캐럿이 이동하여 원하는 요소의 모든 텍스트를 선택한 다음 자동으로 복사 명령을 실행합니다. 사용자는 선택한 텍스트를 볼 수 있으며 선택 / 복사 / 붙여 넣기 옵션이있는 도구 설명이 표시됩니다.

자, 이것은 약간 복잡하고 복사 명령을 내리기에는 너무 번거로워 보이므로 이것이 Apple에서 의도 한 디자인 선택인지 확실하지 않지만 누가 알겠습니까? 그동안 이것은 현재 작동합니다. iOS> = 10 .

이 말한다면, 같은 polyfills 이 하나 이 작업을 단순화하고 (감사 호환 브라우저 교차하게 사용될 수 @Toskan 코멘트에 링크를).

작업 예

요약하면, 필요한 코드는 다음과 같습니다.

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

el이 함수 매개 변수는 <input>또는 여야합니다 <textarea>.

이전 답변 : 이전 iOS 버전

아이폰 OS <10 받는 사람 (실제로 보안 조치입니다) 사파리에 대한 몇 가지 제한이 클립 보드 API는 :

  • 이 화재 copy는 유효한 선택과 이벤트를 cut하고 paste에만 초점을 맞춘 편집 가능한 필드에.
  • .NET이 아닌 바로 가기 키를 통한 OS 클립 보드 읽기 / 쓰기 만 지원합니다 document.execCommand(). "바로 가기 키"는 클릭 가능한 일부 (예 : 복사 / 붙여 넣기 작업 메뉴 또는 사용자 정의 iOS 키보드 단축키) 또는 물리적 키 (예 : 연결된 블루투스 키보드)를 의미합니다.
  • ClipboardEvent생성자를 지원하지 않습니다 .

따라서 (적어도 현재로서는) Javascript를 사용하여 iOS 기기의 클립 보드에있는 일부 텍스트 / 값을 프로그래밍 방식으로 복사 할 수 없습니다 . 사용자 만이 복사 여부를 결정할 수 있습니다.

그러나 프로그래밍 방식으로 무언가를 선택할 수 있으므로 사용자는 선택 항목에 표시된 "복사"도구 설명 만 누르기 만하면됩니다. 이것은 위와 똑같은 코드로 달성 할 수 있습니다 execCommand('copy'). 실제로 작동하지 않을.


몇 가지 솔루션을 검색했고 실제로 작동하는 솔루션을 찾았습니다. http://www.seabreezecomputers.com/tips/copy2clipboard.htm

기본적으로 예제는 다음과 같을 수 있습니다.

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

문제 : iOS Safari document.execCommand('copy')contentEditable컨테이너 내의 텍스트 만 허용 합니다 .

솔루션 : iOS Safari를 감지 contentEditable하고 document.execCommand('copy').

아래 기능은 모든 브라우저에서 작동합니다. CSS 선택기 또는 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>


이것은 내 크로스 브라우저 구현입니다.

아래 스 니펫을 실행하여 테스트 할 수 있습니다.

예:

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>

참고 : 시간 초과 또는 비동기 이벤트와 같이 사용자가 시작하지 않으면 작동하지 않습니다!

click버튼 이벤트에서 호출 된 것과 같은 신뢰할 수있는 이벤트에서 가져와야 합니다.


내 솔루션을 확인하십시오.

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/

도움이되기를 바랍니다.

문안 인사.


내 솔루션은이 페이지의 다른 답변을 결합하여 만들어졌습니다.

다른 답변과 달리 페이지에 이미 요소가 있어야 할 필요는 없습니다. 자체 텍스트 영역을 만들고 나중에 엉망을 정리합니다.

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

좋은 것, 여기에 누군가가 관심이있는 경우를 대비 한 typescript 리 팩터가 있습니다 (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 };

이것은 읽기 전용 입력 요소로 나를 위해 일했습니다.

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

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

    document.execCommand('copy');
};

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


이것이 나를 위해 일한 것입니다. 코드는 모든 최신 브라우저에서 테스트되었으며 작동합니다.

function copyToClipboard(textToCopy) {
  var textArea;

  function isOS() {
    //can use a better detection logic here
    return navigator.userAgent.match(/ipad|iphone/i);
  }

  function createTextArea(text) {
    textArea = document.createElement('textArea');
    textArea.readOnly = true;
    textArea.contentEditable = true;
    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 copyTo() {
    document.execCommand('copy');
    document.body.removeChild(textArea);
  }

  createTextArea(textToCopy);
  selectText();
  copyTo();
}

The idea is to create a fake text area, add it to DOM, set contentEditable & readOnly as true. Create a range to select the desired element and add it to the window’s selection. Set the selection range for the entire element. And then run execCommand('copy'). You may notice a huge number (999999) inside setSelectionRange() method. Well, it is to cover anything that could be inside the element. Read more about range from MDN Docs: https://developer.mozilla.org/en-US/docs/Web/API/Range

Test run (works in the following device/browser combination)

iPhone (iOS >= 10) - Safari, Chrome

Android - Chrome, FF

Mac - Chrome, FF, Safari

Windows - Chrome, IE, FF

I have not mentioned versions specifically because I tested on the latest versions available to me at the time of writing this post. Here's a detailed write of the same: https://josephkhan.me/javascript-copy-clipboard-safari/


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

참고URL : https://stackoverflow.com/questions/34045777/copy-to-clipboard-using-javascript-in-ios

반응형