【種樹】複製網頁文字時,加上網站的作者與網址

之前興起實作了版權訊息的顯示時,有發現有些網站除了顯示版權訊息外,還會在複製網頁內容時,自動加上版權聲明、作者與網址等資訊。當時我覺得頗有趣,決定要來研究看看如何實作。

老樣子我把採坑的過程都寫了下來,如果只想知道最後的結果就直接拉到底吧。

剪貼簿 DOM 事件

既然行為牽扯到複製與貼上,我第一個反應就是翻翻跟剪貼簿相關的 DOM 事件類型,果然找到一些可以用事件分別是:copypaste。想了下我的應用情境,我應該是要在它複製時,加上版權訊息,畢竟執行貼上時應該已經離開這個網站了,不會再次觸發 DOM 事件。

這簡單用 EventListenter 就好:

1
2
3
document.addEventListener('copy', function (evt) {
    // ToDo: append source hyperlink
});

另外, 這樣寫法也行:

1
2
3
4
5
document.body.oncopy = function () {
    setTimeout( function () {
        // ToDo: append source hyperlink
    }, 100)
}

取得複製並修改文字

取得文字

根據找到的資料,剪貼簿的資料儲存在 clipboardData 物件中,可以藉由 getData() 方法並傳入指定資料格式以取得數據:

1
2
3
4
document.addEventListener('copy', function (evt) {
    let text = clipboardData.getData("text/plain");
    console.log(text);
});


不過,這樣直接硬幹似乎有點問題,我遲遲沒看到應該出現的 log,反而出現 Error:

Error

細看了下介紹,原來是瀏覽器的問題。文件中有提到,clipboardData 這個物件,在 IE 中是屬於 window 物件的屬性;但對於其他瀏覽器來說,此物件是屬於 event 的屬性。所以我嘗試改寫了剛剛程式,多了個判斷式:

1
2
3
4
5
document.addEventListener('copy', function (evt) {
    let clipdata = evt.clipboardData || window.clipboardData;
    let text = clipdata.getData("text/plain");
    console.log(text);
});


不過,這樣出來的值卻是 null 的,或許跟瀏覽器的版本有關?所以我又翻了些資料發現相關的寫法五花八門,有諸如:
event.originalEvent.clipboardData.getData('text');
window.event.clipboardData.getData('text');
…等寫法,不過這些寫法不是 Error 就是 null(沮喪 😔)。


最後終於找到一個可用的寫法:

1
2
3
4
document.addEventListener('copy', function (evt) {
    let text = navigator.clipboard.readText();
    console.log(text);
});

但這個只能在 Chrome 上運作,而且即便在 Chrome 上也必須先得到使用者允許授權才能讀取:

使用者允許授權


所以我換了個想法,改用了 document.getSelection。不同於前面的實作方法,是從剪貼簿中取值,在進行複製前有一個必備的前行動作–反白,這個方法就是將反白的文字取出。

1
2
3
4
document.addEventListener('copy', function (evt) {
    let text = document.getSelection().toString();
    console.log(text);
});

修改文字

搞定文字取出後,下一步就是對文字動手腳後回填。這部分就真的得仰賴剪貼簿 clipboardData 了,還好這個時候它沒有跟我鬧脾氣,順利回填了:

1
2
3
4
5
6
7
8
9
10
11
document.addEventListener('copy', function (evt) {
    let text = document.getSelection().toString();
    if (text) {
        text = text + "\n\n" 
        + "=========================================\n"
        + "{網站資訊}"
    }  
    let clipdata = evt.clipboardData || window.clipboardData;        
    clipdata.setData("text",text);
    evt.preventDefault();
});

就此,功能終於搞定了!(灑花)

參考資料

  1. 小火柴的蓝色理想 (2016-09-18)。深入理解DOM事件类型系列第四篇——剪贴板事件。檢自 博客园 (2021-11-23)。
  2. JS教程 (2018-10-07)。複製網頁內容,貼上之後自動加上網址的實現方法(指令碼之家特別整理)Script。檢自 IT閱讀 (2021-11-23)。
  3. (2018-06-28)。js 剪下板應用clipboardData詳細解析。檢自 程式前沿 (2021-11-23)。
  4. GiorgosK (2018-04-14)。window.clipboardData.getData(“Text”) doesnt work in chrome。檢自 Stack Overflow (2021-11-23)。
  5. Element: copy event。檢自 Web APIs|MDN (2021-11-23)。
  6. pj2452 (2015-01-02)。javascript - “Unable to get property ‘getData’ of undefined or null reference” in IE but not Chrome。檢自 Stack Overflow (2021-12-02)。
  7. MGA (2017-01-16)。javascript - Uncaught TypeError: Cannot read property ‘getData’ of undefined。檢自 Stack Overflow (2021-12-02)。
  8. MaxLeeBK (2021-09-25)。那些被忽略但很好用的 Web API / Clipboard。檢自 iT 邦幫忙 (2021-12-02)。

更新紀錄

最後更新日期:2022-04-29
  • 2022-04-29 發布
  • 2021-12-02 完稿
  • 2021-11-23 起稿