最近漲停科技公司實習,由於backend基礎太弱。。。強行前端了一把。。搞了兩周才搞下頁面裡copy的功能,期間有些瑣碎,恐忘,記錄在此。
目前copy主流有四種方式:ZeroClipboard,Clipboard.js,execCommand,setData,再就是其他只支持IE的雞肋法了不在此討論。。
概況:
ZeroClipboard 就是常說的Flash法,通過加載一個Flash,讓其訪問系統剪貼板來繞過絕大多數系統的權限限制,然而體積稍微龐大些
Clipboard.js 近幾年使用較多,體積相對小,兼容性可以接受,使用還比較方便。
execCommand 新興勢力,safari等主流正在努力兼容,是個好東西。
setData 太老。。一般不太用,基本只適合IE
兼容性:
ZeroClipboard 兼容性最好,能全面兼容chrome/ FireFox/ IE/ 甚至Safari 這種“友好”的浏覽器
Clipboard.js和execCommand兼容性相似,兼容chrome/ FF/ IE>9/ Safari新版(不太懂Safari版本號如何算。。感覺15年以後的都可以)
setData 僅IE
體積:
ZeroClipboard 插件較大,230KB
Clipboard.js 較小,4KB
execCommand是document方法,不用插件直接搞
雖說體積有差,加載起來速度差不多的其實。。話說git好像就是用的ZeroClipboard
Clipboard.js 實驗經過:
直接忽略胖胖的Flash法,,先盯上的Clipboard.js,用起來著實簡單,先引用壓縮版:
<script src="dist/clipboard.min.js"></script>
新建Clipboard對象(順便:'.btn'給所有class="btn"的元素都加了監聽,其他用法可查JS)
var clipboard = new Clipboard('.btn'); //可以自己加些處理 clipboard.on('success', function(e) { console.info('Action:', e.action); console.info('Text:', e.text); console.info('Trigger:', e.trigger); e.clearSelection(); }); clipboard.on('error', function(e) { console.error('Action:', e.action); console.error('Trigger:', e.trigger); });
HTML裡這樣就OK了
<button class="btn" data-clipboard-target="#foo">
使用清爽,測試通過,然而項目只有一個地方用到copy,為了他加個插件真是不優美。。於是終於找到了近期出現的execCommand()大法 (生在了好時代Orz)
execCommand()大法:
其實只需要選中要復制的內容,執行document.execCommand('copy', false, null)就好了。execCommand裡可以跑很多例如paste等方法,第一個參數是方法名,第二個是是否展示默認ui,第三個是可選參數列表,對copy來說後兩個都用不到。
根據兼容不同,執行後可能的情況(涉及返回值):
1.不支持execCommand:拋出異常 2.不支持copy方法:返回false 3.成功:true
因此框架可以這樣寫:
copy_target.focus(); copy_target.select(); try{ if(document.execCommand('copy', false, null)){ //success info } else{ //fail info } } catch(err){ //fail info }
給用戶的反饋用的jquery的tooltip,然後寫成一個function就是如下:
function copy(copytargetid,copybtnid){ var cpt = document.getElementById(copytargetid); var cpb = document.getElementById(copybtnid); $(cpt).focus(); $(cpt).select(); try{ if(document.execCommand('copy', false, null)){ $(cpb).tooltip({title:"copied!", placement: "bottom", trigger: "manual"}); $(cpb).tooltip('show'); cpb.onmouseout=function(){$(cpb).tooltip('destroy')}; } else{ $(cpb).tooltip({title:"failed!", placement: "bottom", trigger: "manual"}); $(cpb).tooltip('show'); cpb.onmouseout=function(){$(cpb).tooltip('destroy')}; } } catch(err){ $(cpb).tooltip({title:"failed!", placement: "bottom", trigger: "manual"}); $(cpb).tooltip('show'); cpb.onmouseout=function(){$(cpb).tooltip('destroy')}; } }
用的時候直接
<button id="cpbtn" onclick="copy('cptar', 'cpbtn')">copy</button>
即可
到此還沒有結束。。。
項目用的vue,於是需要做成vue的method,又是用coffee寫的,改了下語法,在初次渲染的html中測試通過了,然後。。。我的copy妞是個vex模態框。。button是寫在vex.dialog.open的message裡的,message是個字符串,彈窗時候強注一段html。而且vue函數是只在渲染階段綁定,所以。。。初次vue渲染的時候不會識別到字符串中的v-on:click,無法綁定。。於是不能從button元素直接調。
決定搞一個隱藏input中繼一下,最後終於用比較優美的姿勢實現了。。。(上次是直接在message裡強行注入script。。。涉及script嵌套還加了個轉義<\/script>,結果丑的一bi。。)
button裡 onclick="document.getElementById('copyrelay').select()",input裡@select('copy(...)')(@是vue的v-on:的縮寫)。
終於測試一切完好,天真的以為加個display: none就大功告成。。結果發現跪了
原來是display:none的元素並不能被select。。
同樣的,也不能focus, change等等,於是順著onerror等事件挨個試了一遍。。發現貌似只有onclick work。。。
另外還順帶試了一下,<input type="hidden"/>也是不能用那些事件;即使正常顯示元素,value=""的話也不能觸發select。
當然,至於是.select()沒有成功,還是元素沒有觸發select事件,還是沒有觸發v-on:select,有待確定,有時間可以試一下。
Anyway,最終代碼:
<input id="copyrelay" style="display: none;" @click=“copy('cptg','cpbt')”/> <!--vex.dialog.open的message中:--> <input id="cpbt" type="button" onclick="document.getElementById('copyrelay').click()"/> <input id="cptg" value="copy test" readonly/>
method中的copy函數如上所提,轉為coffee。
我這個偽frontend太弱了。。還是希望給貴司多搞點貢獻。。。
感謝lrx,lyy,P8,zzl,xxm犇們Orz。。。
就這樣。