最近項目新增需求:用戶可以拖拽頁面上的圖片文件到word文檔。
當操做瀏覽器裏拖拽圖片至別的程序,在word文檔中展現出獲取到的只是圖片的url地址,而非預期的圖片文件。在現有的拖拽事件所提供api沒法知足需求的狀況下,換一個思路走:嘗試將圖片複製到剪貼板。html
對於原生js的複製操做,已有封裝好的庫clipboard.js,可是封裝得太死,沒法知足更多定製化的需求,主要表如今如下兩點:node
參考clipboard.js源碼,瞭解了實現原理後(其實很是簡單!:) ),咱們就能本身動手封裝一個複製方法:git
Range表示包含節點和部分文本節點的文檔片斷。最多見的就是用戶在瀏覽器拖動鼠標選擇的內容(user selection)es6
好比上圖這塊藍色高亮區域。github
在現代瀏覽器中(IE9以上),你能夠經過Document.createRange()方法或者new Range()建立一個Range對象;當須要獲取user selection時,你應該使用window.getSelection()方法獲取Selection對象。web
有點懵?chrome
剛瞭解了Range對象,而Selection對象又是什麼?閱讀了文檔以後,仍是疑惑它們之間的區別?windows
Selection對象表示用戶的選擇,而Range對象則表示文檔的連續部分,與任何視覺表示無關。一個Selection對象幾乎可由0到多個Range表示出來,固然,Range對象也能獨立於Selection而被徹底的建立和修改。api
html部分:數組
<p> 這是一段文字 AAAAAAAAAA BBBBBBBBBB <span id="range">Range</span> </p> <input id="input" type="text"> <button id="button1">選擇文字後點擊</button> <button id="button2">點擊後將選中指定的節點</button>
js部分:
var btn1 = document.getElementById('button1'), btn2 = document.getElementById('button2'), input = document.getElementById('input'), rangespan = document.getElementById('range'); var selection = window.getSelection(), range = document.createRange(); btn1.addEventListener("click", function(event) { input.value = selection.toString(); }); btn2.addEventListener("click", function(event) { range.selectNode(rangespan); selection.removeAllRanges(); //刪除包含在selection本來的range,也就是取消用戶選中的範圍 selection.addRange(range); //讓選中部分變成咱們本身定義的節點內容 });
演示地址:
https://jsfiddle.net/muvhqcnf...
一點就會 :)
Microsoft提供了相似的TextRange接口。
在實際代碼部分會展現Microsoft TextRange的基本使用。
execCommand方法容許運行命令來操縱可編輯區域的內容。該方法的第一個參數是命令的名稱,參數類型爲DOMString。
在這裏,咱們將利用execCommand方法的copy命令實現複製選中的內容:
document.execCommand('copy')
execCommand API起源於IE,後來被添加到HTML5(HTML Editing APIs),在各瀏覽器的表現會有不一樣。更多請查看文檔。
咱們回到前面的演示代碼,將btn1的點擊事件替換成execCommand命令:
btn1.addEventListener("click", function(event) { //input.value = selection.toString(); document.execCommand('copy'); });
拖動鼠標選擇文字,點擊按鈕後看看能粘貼出什麼:)
還記得前面的例子裏,咱們經過range的selectNode(node)方法獲取節點, 再使用selection的removeAllRanges()方法和addRange(range)將節點替換咱們獲取的節點。在這裏,咱們一樣能夠這樣選中咱們目標的img節點:
const getSelect = targetNode => { if (window.getSelection) { //chrome等主流瀏覽器 var selection = window.getSelection(); var range = document.createRange(); range.selectNode(targetNode); selection.removeAllRanges(); selection.addRange(range); } else if (document.body.createTextRange) { //ie var range = document.body.createTextRange(); range.moveToElementText(targetNode); range.select(); } }
爲了避免浪費性能,咱們使用事件委託到但願被複制的節點上。這裏對傳入的nodeName進行處理,方便自由的控制被複制一個或多個節點類型。默認爲<img>。
const clipboardHandler = (nodeName, event) => { event = event || nodeName; //不傳參時 const type = Object.prototype.toString.call(nodeName).replace(/\[object\s|\]/g, ''); const target = event.target || event.srcElement; var result = false; switch (type) { case 'String': result = (target.nodeName.toLowerCase() === nodeName); break; case 'Array': result = nodeName.some(item => target.nodeName.toLowerCase() === item); break; case 'Object': nodeName = null; default: result = (target.nodeName === 'IMG'); } if (result) { //調用以前封裝好的getSelect方法 getSelect(target); document.execCommand('copy'); } }
調用:
[element].addEventListener('mousedown', clipboardHandler); //預備拖動圖片按下鼠標時執行復制
傳遞參數(字符串或數組):
var [somename]Handler = clipboardHandler.bind(null, [nodeName]); [element].addEventListener([eventType],[somename]Handler);
已驗證在chrome和ie8上可行(ie8須要對es6語法與bind和addEventListener方法進行pollyfill)
但願可以幫助到你:)