[轉載] [Angular] 複製到剪貼簿功能
https://blog.poychang.net/click-button-copy-to-clipboard-in-angular/
之前寫過一篇只用 JavaScript 實作一鍵複製的作法,在了解原理後,想要在 Angular 中也來實作同樣的功能,其實也很簡單唷!
先提一下,複製、貼上這動作是由瀏覽器所提供的,所以需要使用到
document和window這個瀏覽器物件。
複製文字這件事,基本上三個動作:
- 找到目標區塊
- 選取目標
- 執行複製
找到目標區塊
使用 JavaScript 要找到 DOM 中的某段區塊,可使用 document.querySelector() 方法,搭配 CSS 選擇器來尋找目標區塊,這樣就可以取得所要的 DOM 節點內容。
在 Angular 中也可以使用上面的方法來尋找區塊,但更推薦的作法是使用 Angular 內部的 DOCUMENT Token,透過注入的方式來使用 document 全域物件。
這樣的作法可以用在 AOT,或在寫測試時,可以用模擬的方式來取代全域物件。
// 1. 載入 DOCUMENT Token
import { DOCUMENT } from "@angular/platform-browser";
// ...
// 2. 使用 Token 注入至元件中
constructor( @Inject(DOCUMENT) private dom: Document) { }
// ...
// 3. 設計選取區塊的方法
selectText(selector: string): void {
const element = this.dom.querySelector(selector);
}
到目前為止,我們在 selectText() 裡面已經可以取到目標區塊並存在 element 裡面了。
由於
document和window都是瀏覽器提供的全域物件,但 Angular 只有提供DOCUMENTToken 來實作注入,window了話,則需要自己額外設計。為了簡化問題,這裡先直接用
window全域物件來處理。
選取目標
具有 select() 方法的 DOM 元素
目前 DOM 元素中,只有 HTMLInputElement 和 HTMLTextAreaElement 有選取文字的方法 select(),所以針對這兩種 DOM 元素滿容易處理的,直接使用該方法就可以選到目標文字。
其他 DOM 元素
但除上述兩者外,我們還希望能夠複製其他 DOM 元素的文字時,就需要透過 document.Range 物件和 window.getSelection() 方法,藉此來選取目標。
這邊稍微解釋一下 Range 和 Selection 這兩個物件的差別:
Range物件所包含的是 DOM 裡面的元素,會包含節點及子節點的內容。Selection物件則是從 Range 物件中,取得選取到的文字,如同使用者用滑鼠選取特定文字般,並記錄選取的起迄位置。
所以這兩者的運作環境是不一樣的,Range 在 DOM 裡面去選取區塊,而 Selection 比較像是瀏覽器功能列上的 Select all 功能,不過他不是全選,而是針對 Range 物件去找到選取目標。

如此一來 selectText() 改成如下:
// 3. 設計選取區塊的方法
selectText(selector: string): void {
const element = this.dom.querySelector(selector);
const isInputElement = element instanceof HTMLInputElement;
const isTextAreaElement = element instanceof HTMLTextAreaElement;
if (isInputElement || isTextAreaElement) {
(element as HTMLInputElement).select();
} else {
let range = this.dom.createRange();
range.selectNodeContents(element);
let selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
}
執行複製
複製的行為是交由瀏覽器來處理,因此需要調用 document.execCommand() 方法,並告訴瀏覽器要執行 copy 這個動作。這裡的動作很簡單,一行就可以完成,另外再加上一些狀態訊息的輸出。
// 4. 執行瀏覽器的複製指令,複製選取到的文字
execCopy() {
try {
const copyStatus = this.dom.execCommand('copy');
const message = copyStatus ? 'copied' : 'failed';
console.log(message);
} catch (error) {
console.log(`${error}`);
}
window.getSelection().removeAllRanges();
}
這個方法最後調用了 removeAllRanges() 方法,這是取消選取的效果,讓使用者察覺不出來到底發生什麼事。
完整程式碼
參考資料:
留言
張貼留言