鼠標一鍵點擊實現頁面文本全選和複製

需求背景

有些頁面上的數據用戶常常須要全選而後進行復制的工做,用戶通常須要兩步操做,第一步是選中文本,用戶能夠經過三次點擊或着點擊後拖動鼠標來進行選中,第二步則是點擊右鍵選擇複製,或者利用鍵盤快捷鍵。爲了提升用戶體驗,咱們想要讓用戶點擊相關文字時候,自動全選而且完成複製操做。javascript

自動全選.gif

1. 文本全選實現方案

1.1 利用CSS user-select 屬性

CSS屬性 user-select 控制用戶可否選中文本css

auto | text | none | contain | allhtml

contain 在不少瀏覽器中例如Chrome中時不支持的,在這裏咱們用 user-selet: all 就可以實現文本全選的功能。vue

優點: 能夠很是靈活,並且十分簡單,一個語句就可完成功能。java

不足: 做爲優化需求的時候,須要修改原有代碼。也就是若是要在原來的已經寫好的頁面中加入此功能,須要找到每個具體的位置,而後添加對應的className或者增長css的行間樣式。node

1.2 利用Javascript光標對象selection

selection 表明了當前激活選中區,即高亮文本塊,和/或文檔中用戶可執行某些操做的其它元素。正則表達式

export default () => {
  // 監聽鼠標的click事件
  document.addEventListener('click', (e: Event) => {
    // 獲取到鼠標點擊的dom元素
    const span = e.target;
    // 獲取dom元素中的的innerText的值
    const value = (span as HTMLElement).innerText;
    // 遍歷全部配置的正則表達式
    for (const reg of Object.values(regObject)) {
      if (reg.test(value)) {
        // 驗證經過了正則的值是不是span元素或者是div元素,由於不想在輸入框也有此功能
        if ((span as HTMLElement).localName === ('span' || 'div')) {
          // 獲取一個Selection對象
          const selection = window.getSelection();
          // 先清空一下以選擇的內容
          selection?.removeAllRanges();
          // 建立一個range對象
          const range = document.createRange();
          // 讓range對象包含一個node的內容
          range.selectNodeContents(span as HTMLElement);
          // 向selection中添加一個區域(range)
          selection?.addRange(range);
        }
      }
    }
  });
};
複製代碼

技術方案實現的思路:api

  1. 監聽鼠標click事件
  2. 定義文本的正則匹配規則,例如此需求中是爲了全選Location ID,正則爲/^[A-Z]{3}-[A-Z](-[0-9]{1,2})+$/, 此正則表達式用到的符號的意思爲:

^ 表示(脫字符)匹配開頭,在多行匹配中匹配行開頭
[A-Z] 等價於全部大寫字母
{m} 等價於{m,m},表示出現m次
[0-9] 等價於全部數字
{1,2} 等價於前面的內容出現一到兩次
+等價於{1,},表示出現至少一次
$(美圓符號)匹配結尾,在多行匹配中匹配行結尾瀏覽器

  1. 若是文本經過正則校驗,那麼再判斷元素的類型,此例子中只但願獲取div和span元素中的文本,因此利用了 localName 這個屬性來判斷元素類型了
  2. 一系列校驗完成後,咱們獲取 selection 對象,利用 removeAllRanges 清空一下內容(至關於初始化
  3. 再經過 createRange 獲取range對象,利用 range 對象的 selectNodeContents 來獲取範圍
  4. 最後使用 addRange 來讓文本信息高光

優點: 能夠在App.vue入口文件一次添加,不須要修改原有代碼markdown

不足: 所須要高亮的數據須要有必定的結構特色,好比數據須要有必定的規則。還有就是全局添加click的監聽事件,會增長一點性能消耗

文本全選實現方案總結

兩種方案都有優缺點,須要結合具體的場景,需求來選取合適的方案,本文也只是提供一種思路的參考。

2. 自動觸發複製的實現方案

實現自動將內容複製到剪貼板中有三種方法:

  • Document.execCommand()方法
  • 異步的 Clipboard API
  • copy事件和paste事件

2.1 Document.execCommand()方法

Document.execCommand() 是操做剪貼板的傳統方法,各類瀏覽器都支持。

它支持複製、剪切和粘貼這三個操做。

document.execCommand('copy')(複製)
document.execCommand('cut')(剪切)
document.execCommand('paste')(粘貼)

Document.execCommand() 方法的缺點是隻能複製高亮文本的內容,不能夠自定義信息放入剪貼板中, 並且這種方式只支持同步操做。可是對於咱們這個需求,這種方式已經足夠了。

2.2 異步的 Clipboard API

Clipboard 對象的全部操做都是異步的,返回 Promise 對象,不會形成頁面卡頓。

const clipboardObj = navigator.clipboard;

並且,它能夠將任意內容(好比圖片)放入剪貼板。擁有如下4個方法:

Clipboard.readText() 方法用於複製剪貼板裏面的文本數據。
Clipboard.read() 方法用於複製剪貼板裏面的數據,能夠是文本數據,也能夠是二進制數據
Clipboard.writeText()方法用於將文本內容寫入剪貼板
Clipboard.write()方法用於將任意數據寫入剪貼板,能夠是文本數據,也能夠是二進制數據

這樣的操做更加靈活,高效。可是缺點是 Chrome 瀏覽器規定,只有 HTTPS 協議的頁面才能使用這個 API, 而咱們這個項目不是這種協議的,因此沒法使用此 API。

2.3 copy事件

此方法須要首先利用2.1中的document.execCommand('copy')方法觸發一個複製操做,而後利用監聽copy進行處理。

document.addEventListener('copy', async (e) => {
      e.preventDefault();
      try {
        let clipText = ''
        ...
        // 將自定義的內容放入剪貼板中 
        e.clipboardData.setData('text/plain', clipText)
      } catch (err) {
        console.log(err);
      }
   });
複製代碼

此需求並非這種方法的應用場景,此方法的應用場景以下:

當你但願自定義放入一些內容在剪貼板中,可是你的項目又並非 HTTPS 的協議,就只有使用這種方法了。但須要注意一點, 因爲 2.1 Document.execCommand()方法 是隻支持同步的,因此若是在異步操做裏面調用是沒有用的,那麼若是你想放入剪貼板中的內容是須要異步請求的,再請求以後想要直接調用複製操做的話就會失效。舉代碼例子:

async getData () {
  try {
    await this.getClipboardData();
    // 這裏的複製操做觸發是無效的
    document.execCommand("Copy")
  }
}
複製代碼

因此交互需變成,先保存異步回來的數據,等數據回來之後,再經過一個按鈕或其餘方式,同步出發複製操做。

自動複製.gif

自動觸發複製的實現方案總結

三種方式都有其適合的應用場景,但第三種 copy 事件的方式會污染真正的複製操做,仍是不太建議使用,只能算是一種兜底的方案。

引用

剪貼板操做 Clipboard API 教程
MDN: user-select
MDN: Selection
MDN: Document.createRange()
JS正則表達式完整教程
javascript實現鼠標點擊自動選中點擊元素內的文字

相關文章
相關標籤/搜索