在最近的 Web 開發中, 有遇到使用Clipboard
的場景。即在 B 側 Web 業務中, 對於複雜頁面的配置, 但願提供複製粘貼
功能。 思考了幾種方案:javascript
依賴後臺接口, 新增數據 從需求角度來說, 比較簡單的方案就是調用後臺接口, 生成一條新數據, 用戶在新增數據上進行修改便可。此方法適用於同一環境(product
或devnet
)的複製粘貼。前端
前端本地存儲, 新增操做時檢測 在用戶觸發複製行爲時, 將數據存入本地localStorage
, 當用戶進行新增操做時, 檢測localStorage
是否有已複製數據。因爲是前端保留了複製的數據, 就能夠不用考慮後臺的環境問題, 可使用測試環境與現網環境之間的複製粘貼。 但這裏的測試環境與現網環境切換依賴了代理配置。對於經過不一樣域名區分環境的應用(例如, xxx.xx.com or test.xxx.xx.com), localStorage 被同源策略限制, 沒法跨域讀取數據。java
使用 Clipboard 在上述前端本地存儲方案的基礎上, 想到了clipboard
的方案。相似於淘口令的方案, 將數據存入 Clipboard, 而後在新增數據時, 檢測 Clipboard 便可。使用 Clipboard 是利用了系統的數據存儲, 也解決了不一樣域名間的跨域問題。web
docment.execCommand
是一個能夠操做可編輯內容區域
的同步方法。api
// 語法
bool = document.execCommand(aCommandName, aShowDefaultUI, aValueArgument);
複製代碼
方法第一個參數aCommandName
傳入命令字, 包括了copy
, cut
, bold
, backColor
等操做。方法第二個參數aShowDefaultUI
指是否展現用戶界面, 通常不使用這個參數。方法第三個參數aValueArgument
是傳入操做命令時的一些額外參數。方法返回了一個 bool 值, 描述操做是否成功。詳細狀況能夠參考MDN跨域
咱們要作的需求是將須要的內容寫入 Clipboard, 使用的也就是上述提到的copy
瀏覽器
話很少說, 咱們經過代碼看下如何使用這個功能安全
<div>
<input type="text" value="Copy Content"/>
<button onclick="handleClick">copy</button>
</div>
複製代碼
const i = document.querySelector('input');
// 得到焦點
i.select();
document.execCommand('copy');
複製代碼
點擊按鈕, Copy Content
就會被寫入剪切板, 以後就能夠將剪切板內容內容複製粘貼到其餘地方了。app
講到這裏, 你們就會好奇, "爲何要用input
組件呢?", 固然啦, 其實用textarea
也是能夠的。上述提到了可編輯區域
, 只有input
, textarea
或具備contenteditable
屬性的元素才能夠被execCommand
操做dom
那若是不想頁面中出現可編輯區域
, 那能夠怎麼辦呢?
/** * @description 複製內容到剪切板 * @param {string} content 文本內容 */
function copy2Clipboard = content => {
const dom = document.createElement('input');
dom.value = content;
document.body.appendChild(dom);
dom.select();
document.execCommand('copy');
document.body.removeChild(dom);
};
複製代碼
可使用如上取巧方法便可~
上述document.execCommand
是一個同步操做, navigator.clipboard
是瀏覽器提供的剪切板 API, 能夠經過此 API 實現剪切板的操做, 各大瀏覽器廠商最近也都支持了navigator.clipboard
API.
那麼如何使用呢? 咱們仍是從代碼一一道來。
navigator.permissions.query({ name: 'clipboard-write' }).then(function(result) {
// 多是 'granted', 'denied' or 'prompt':
if (result.state === 'granted') {
// 可使用權限
// 進行clipboard的操做
navigator.clipboard.writeText('Clip Content').then(
function() {
/* clipboard successfully set */
// 成功設置了剪切板
},
function() {
/* clipboard write failed */
// 剪切板內容寫入失敗
}
);
} else if (result.state === 'prompt') {
// 彈窗彈框申請使用權限
} else {
// 若是被拒絕,請不要作任何操做。
}
});
複製代碼
navigator.permissions
是瀏覽器向用戶請求使用敏感接口的 API, 調用接口會向用戶彈出 Prompt 框, 詢問用戶是否可使用相關權限。 上述代碼先查詢請求使用了clipboard-write
剪切板的使用權限。 在權限經過以後, 調用了navigator.clipboard.writeText
方法。
navigator.clipboard
API 被計劃用於取代document.execCommand
接口, 因此也建議使用clipboard
API 去進行複製操做
。
代碼以下:
async function copy2Clipboard(content) {
const res = await navigator.permissions.query({ name: 'clipboard-write' });
if (res.state === 'granted') {
return navigator.clipboard.writeText(content);
}
return Promise.reject(res);
}
複製代碼
關注【IVWEB社區】公衆號查看最新技術週刊,作更優秀的本身!
考慮到安全緣由, document.execCommand('paste')
操做已經被禁止了。
那有什麼辦法能夠讀取剪切板的內容呢?
監聽 paste 事件
document.addEventListener('paste', event => {
// 從event中讀取clipboardData
const pasteContent = (event.clipboardData || window.clipboardData).getData('text');
// do whatever
});
複製代碼
在本需求場景中, 但願能夠由前端讀取的剪切板內容, 而不是用戶主動觸發, 因此這裏就再也不詳述了。
那還有什麼方案呢?
navigator.clipboard.readText
也是瀏覽器提供的剪切板操做 API, 與writeText
相似, 也須要請求剪切板權限。
// 申請使用剪切板讀取權限
navigator.permissions.query({ name: 'clipboard-read' }).then(function(result) {
// 多是 'granted', 'denied' or 'prompt':
if (result.state === 'granted') {
// 可使用權限
// 進行clipboard的操做
navigator.clipboard
.readText()
.then(text => {
console.log('複製粘貼文本: ', text);
})
.catch(err => {
// 讀取剪切板內容失敗
console.error('Failed to read clipboard contents: ', err);
});
} else if (result.state === 'prompt') {
// 彈窗彈框申請使用權限
} else {
// 若是被拒絕,請不要作任何操做。
}
});
複製代碼
首先咱們要申請使用剪切板的clipboard-read
權限, 在得到用戶權限後, 便可經過navigator.clipboard.readText
獲取權限了。
固然監聽paste
事件也是能夠的
document.addEventListener('paste', event => {
event.preventDefault();
navigator.clipboard.readText().then(text => {
console.log('Pasted text: ', text);
});
});
複製代碼
所以, 咱們就能夠將讀取剪切板內容的功能抽象出來:
/** * @description 讀取剪切板內容 * @return {string} */
async function readClipboard() {
const result = await navigator.permissions.query({ name: 'clipboard-read' });
if (result.state === 'granted' || result.state === 'prompt') {
return navigator.clipboard
.readText()
.then(text => text)
.catch(err => Promise.reject(err));
}
return Promise.reject(result);
}
複製代碼
瀏覽器並無提供能夠清理剪切板的接口。若是網站在使用完剪切板內容後, 須要進行清理內容的話, 能夠從新寫入數據
// ...
input.value = ' '; // input的值必須有值, 不能是空字符串
input.select();
document.execCommand('copy')
// 或者使用clipboard
navigator.clipboard.writeText('');
複製代碼
Web操做剪切板內容具備必定的安全風險。瀏覽器爲了保證用戶隱私, 要求使用navigator.clipboard
API必需要接入HTTPS
。
HTTP網站是不支持此接口的, 僅支持document.execCommand('copy')
和監聽paste
事件
從用戶角度考慮, 也建議你們的網站都接入HTTPS
可能會支持更通用的write
與read
方法, 提供二進制數據的寫入等等(例如圖片等)。