本文介紹了JS與剪貼板相關的底層功能模暗。
1. 背景
事情的起因是這樣的沟绪,在從簡書上面找了個別人的文章復制了一些內(nèi)容氧吐,當復制的內(nèi)容超過了一定字數(shù)的時候博个,就發(fā)現(xiàn)粘貼出來的東西多了一些內(nèi)容怀樟,如下圖所示。
由于最近剛好在研究JS的復制剪切盆佣,于是對這個功能進行深入研究往堡。
2. document.execCommand
之前使用了一個插件Clipboard.js實現(xiàn)了JS的復制功能,研究之后發(fā)現(xiàn)是調(diào)用HTML5的document.execCommand共耍,才能實現(xiàn)瀏覽器端的復制功能虑灰。
語法
bool = document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)
返回值
一個 Boolean
,如果是 false則表示操作不被支持或未被啟用痹兜。
參數(shù)
我們這里只需要用到一些簡單的功能穆咐,因此只使用第一個參數(shù)aCommandName
就可以了。
一個 DOMString
字旭,命令的名稱对湃。可用命令列表請參閱文檔遗淳。
命令
這里簡單介紹一些用到的命令拍柒。
copy
拷貝當前選中內(nèi)容到剪貼板。啟用這個功能的條件因瀏覽器不同而不同洲脂,而且不同時期斤儿,其啟用條件也不盡相同。使用之前請檢查瀏覽器兼容表恐锦,以確定是否可用。
cut
剪貼當前選中的文字并復制到剪貼板疆液。啟用這個功能的條件因瀏覽器不同而不同一铅,而且不同時期,其啟用條件也不盡相同堕油。使用之前請檢查瀏覽器兼容表潘飘,以確定是否可用肮之。
paste
在光標位置粘貼剪貼板的內(nèi)容,如果有被選中的內(nèi)容卜录,會被替換戈擒。剪貼板功能必須在 user.js 配置文件中啟用。
從上面的介紹可以看出艰毒,復制功能都是對當前選中內(nèi)容進行的相關操作筐高,這都需要能獲取到當前選中的對象,因此找到了一個新的API丑瞧。
3. Window.getSelection
這個方法是對用戶選擇的文本范圍進行的一些操作柑土。
概述
返回一個 Selection
對象,表示用戶選擇的文本范圍或光標的當前位置绊汹。
語法
const selection = window.getSelection() ;
- selection
是一個Selection
對象稽屏。 如果想要將selection
轉(zhuǎn)換為字符串,可使用String.toString()
方法西乖。
示例
function foo() {
let selObj = window.getSelection();
console.log(selObj);
let selectedText = selObj.toString();
let selRange = selObj.getRangeAt(0);
// 其他代碼
}
-
selObj
是一個Selection
對象狐榔。 -
selectedText
是一個字符串(被選中的文本)。
4. 實現(xiàn)思路
- 首先要響應瀏覽器的
copy
事件获雕,使用e.preventDefault()
阻止默認的復制事件薄腻。 - 在響應瀏覽器的
copy
事件時,通過Window.getSelection()
獲取到當前選中內(nèi)容典鸡。然后使用document.createRange()
保存下此時用戶選中區(qū)的狀態(tài)被廓,以供后面使用。 - 創(chuàng)建一個
<textarea>
標簽萝玷,將他移到屏幕外邊嫁乘,將上一步中的內(nèi)容,放到文本框內(nèi)球碉。并以字符串的形式添加上額外的內(nèi)容蜓斧。(注:為了能在添加的內(nèi)容達到換行的效果,需要使用<textarea>
標簽而不是<input>
睁冬,需要換行處添加'\n'
字符串) - 使用文本框的
setSelectionRange()
將文本框的內(nèi)容選中挎春,使用document.execCommand
將此選中的內(nèi)容進行復制。 - 最后豆拨,使用
selectionObject.addRange(range)
將此前選中的選區(qū)進行選中直奋。(注:此處詳見參考資料3)
5. 實現(xiàn)代碼
此代碼在新版的chorme和firefox均可生效。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>addCopy</title>
<style>
#test {
border: 1px solid #000;
}
</style>
</head>
<body>
<dl id="test">
<dt>
<code>copy</code>
</dt>
<dd>拷貝當前選中內(nèi)容到剪貼板施禾。啟用這個功能的條件因瀏覽器不同而不同脚线,而且不同時期,其啟用條件也不盡相同弥搞。使用之前請檢查瀏覽器兼容表邮绿,以確定是否可用渠旁。</dd>
<dt>
<code>cut</code>
</dt>
<dd> 剪貼當前選中的文字并復制到剪貼板。啟用這個功能的條件因瀏覽器不同而不同船逮,而且不同時期顾腊,其啟用條件也不盡相同。使用之前請檢查瀏覽器兼容表挖胃,以確定是否可用杂靶。</dd>
<dt>
<code>paste</code>
</dt>
<dd>在光標位置粘貼剪貼板的內(nèi)容,如果有被選中的內(nèi)容冠骄,會被替換伪煤。剪貼板功能必須在 user.js 配置文件中啟用。</dd>
</dl>
<p>復制以上黑框內(nèi)的內(nèi)容后在下面textarea粘貼看一下</p>
<textarea rows="4"></textarea>
<script type="text/javascript">
function makeAdditionMessage(targetDom, additionMsg) {
var body = document.getElementsByTagName('body')[0];
//使用textarea可以在添加內(nèi)容的時候產(chǎn)生換行的效果
var hideTextarea = document.createElement('textarea');
body.appendChild(hideTextarea);
hideTextarea.style.position = 'absolute';
hideTextarea.style.left = '-9999px';
hideTextarea.style.top = '-9999px';
targetDom.addEventListener('copy', function (e) {
// 禁止默認的copy事件
e.preventDefault();
var selectionObject = window.getSelection();
var selectString = selectionObject.toString();
// 注意凛辣,這里制作的range光標選中框需要放在 生成新選區(qū)之前進行制作
var range = document.createRange();
range.setStart(selectionObject.anchorNode, selectionObject.anchorOffset);
range.setEnd(selectionObject.focusNode, selectionObject.focusOffset);
// 添加新增的內(nèi)容抱既,并將它們放入剪切板
hideTextarea.value = selectString;
hideTextarea.value += additionMsg;
hideTextarea.focus();
hideTextarea.setSelectionRange(0, hideTextarea.value.length);
var copy = document.execCommand('copy');
// 將此前選中的文本再進行選中
selectionObject.removeAllRanges();
selectionObject.addRange(range);
})
}
var test = document.getElementById('test');
var msg = '\n\n這是額外的第一行內(nèi)容\n這是第二行';
makeAdditionMessage(test, msg);
</script>
</body>
</html>
6. 實現(xiàn)效果
- 選中某些文本進行復制
- 粘貼出來的示意圖