前端模擬使用者的複製操作

descire發表於2019-05-07

一、前言

  使用者在瀏覽網頁的過程中,執行復制操作的場景是非常多的,例如:複製連結地址、複製分享文案等等。

  而前端通過模擬使用者的複製操作,可以減少操作的步驟,進而優化使用者體驗。

  複製操作主要分為以下兩部分:

  • 選中文字:對應使用者通過滑鼠或者觸屏選中文字的操作。
  • 作業系統剪貼簿:對應使用者按下 Ctrl(command) + C 的操作。

二、選中文字

  首先,讀者需要明白,不是所有的文字都可以被選中的(後續會提到),筆者這裡先介紹幾個可以選中文字的情況:

1、input 和 textarea

  由於 input 元素的工作方式因其型別屬性的值而有很大的差異,所以這裡只討論 text 的情況。

  因為 JavaScript 提供了 HTTMLInputElement.select() 方法,所以選中 textarea 和 input 中的內容就變得非常簡單:

  document.querySelector('input').select()
複製程式碼

前端模擬使用者的複製操作

  如果 input 和 textarea 元素附加了 disabled 屬性,那麼其內容是無法被選中的,這種情況最好是將 disabled 替換為 readonly 。

2、div

  div 元素並沒有開箱即用的 select() 方法,這就需要讀者瞭解一個新的物件: Selection 。

  Selection 物件表示使用者選擇文字的範圍以及游標的範圍。關於 Selection 物件,讀者需要了解以下幾個術語:

  • 錨點:選區的起始點。
  • 焦點:選區的終止點。
  • 範圍:文件中連續的一部分。

  與 Selection 物件息息相關的還有一個 Range 物件,它主要用來自定義選區。對於這兩個物件不瞭解的讀者,可以檢視文末給出的參考文獻,接下來,利用 Selection 和 Range 物件實現上述 select() 方法:

  function select (element) {
    const selection = window.getSelection()
    const range = document.createRange()
    range.selectNodeContents(element)
    selection.removeAllRanges()
    selection.addRange(range)
  }
複製程式碼

前端模擬使用者的複製操作

三、作業系統剪貼簿

  document 暴露的 execCommand 方法,可以用來執行作業系統提供的命令,並且這些命令大部分作用於 Selection 物件。

  該方法返回的布林值表示操作是否被支援或者是否被啟用,但是呼叫一個命令之前,不能嘗試使用返回值去校驗瀏覽器的相容性。

  function copyText () {
    let success = true
    try {
      success = document.execCommand('copy')
    } catch (e) {
      success = false
    }
    return success
  }
複製程式碼

  通過 execCommand 執行 copy 命令,可以將上述選中的文字新增到系統剪貼簿中,接下來使用者只需要在使用的地方按下 Ctrl(command) + V 即可貼上該內容。

四、特殊情況的處理

  上述方案基本上可以應對大部分的情況,但是在 HTML 中,部分元素中的文字是無法被選中的,例如:

  <select id="js-select">
    <option value="apple">apple</option>
    <option value="banana">banana</option>
    <option value="peach">peach</option>
  </select>
複製程式碼

  既然 select 元素中的文字無法被選中,那麼就無法呼叫 execCommand 方法,又何談模擬使用者複製該文字呢?

  這裡就需要採用以下套路:

1、獲取需要複製的文字

  首先獲取到需要複製的文字內容,對於 select 元素,其文字內容可以根據 value 屬性獲取:

  const element = document.getElementById('js-select')
  const text = element.value
複製程式碼
2、建立透明元素

  前面提到的 input、textarea 等元素都是可以被選中的,所以這裡筆者選擇建立一個透明的 textarea 來實現接下來的功能:

  function createFakerElement (text) {
    const fakerElement = document.createElement('textarea')
    fakerElement.style.position = 'absolute'
    fakerElement.style.left = '-9999px'
    fakerElement.value = text
    document.body.appendChild(fakerElement)

    return fakerElement
  }
複製程式碼
3、選中文字

  前面也提到選中文字有兩種方式:

  • 對於 input、textarea 元素,可以直接呼叫其 select 方法。
  • 對於大多數元素(input 和 textarea 元素就是特例之一),可以通過 Selection 和 Range 完成選中文字的操作。

  由於上述建立的是 textarea,這裡直接呼叫 select 方法:

  function selectInput (element) {
    return element.select()
  }
複製程式碼
4、作業系統剪貼簿

  前文已經提及,這裡不再贅述。

  接下來只要按照順序執行這些操作即可:

  document.getElementById('js-button').addEventListener('click', () => {
    const element = document.getElementById('js-select')
    // 1、獲取需要的文字內容
    const text = element.value

    // 2、建立透明的 textarea 元素
    const fakerElement = createFakerElement(text)

    // 3、選中相應的文字
    selectInput(fakerElement)

    // 4、執行作業系統剪貼簿的 copy 命令
    const success = copyText()

    if (success) {
      console.log('複製成功')
    } else {
      console.log('複製失敗')
    }

    document.body.removeChild(fakerElement)
  }, false)
複製程式碼

五、總結

  由上文可知,前端模擬使用者的複製操作主要涉及兩方面的知識:

  • 利用 Selection 和 Range 物件完成文字選中操作,比較特殊的是 input 和 textarea 元素自帶 select 方法實現該操作。
  • 通過 document.execCommand 方法呼叫 copy 命令將內容儲存到系統剪貼簿中。

  其中 document.execCommand 方法主要作用於 Selection 物件,所以當元素無法被選中時,該複製命令則無法達到預期的效果。

  前面也到了 disabled 屬性以及 select 元素這樣的特例,相比較下,通過建立一個透明的 textarea 來模擬複製操作的方案可用性更高。

  參考文獻

  相關文章推薦

  寫在最後

  如果本文對您有幫助,點個贊吧!也歡迎小夥伴們關注我的訂閱號 漫談大前端

相關文章