大家好,我是若川。持續組織了近一年的源碼共讀活動,感興趣的可以?點此加我微信ruochuan12?參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》?包含20余篇源碼文章。歷史面試系列。另外:目前建有江西|湖南|湖北
籍前端群,可加我微信進群。
本文來自讀者@NewName 的投稿。(基本我出一期源碼共讀就寫一篇筆記的小伙伴),他自己曾說學到很多,同時更熱愛學習了。
日常開發中我們有時會遇到拷貝粘貼的功能,筆者還記得曾經使用過react-copy-to-clipboard 和 vue-clipboard2。最近在看vueuse的時候發現了useClipboard就簡單研究了一下,日后vue3項目中如果有使用場景可以用一下。
1.原生Clipboard
在看useClipboard源碼之前,需要一些前置知識,那就是原生Clipboard的API。首先通過一張圖概覽一下瀏覽器原生Clipboard的相關知識:對上圖涉及的知識逐一解釋:
剪貼板 Clipboard API 提供了響應剪貼板命令與異步讀寫系統剪貼板的能力。
從權限 Permissions API 獲取權限之后,才能訪問剪貼板內容。
Clipboard API 包括異步剪貼板 API(AsyncClipboard API)和 剪貼板事件 API(Clipboard Event API)。
Clipboard讀取剪切板有兩個方法read()和readText()分別用于讀取數據(比如圖片)和文本;寫入剪切板有兩個方法write()和writeText()分別用于將任意數據寫入和將文本寫入。
ClipboardEvent接口描述了與修改剪切板相關信息的事件,包括剪切,復制和粘貼。
更多關于Clipboard API的細節以及兼容性問題您可以訪問MDN文檔詳細學習。看一段示例代碼:
navigator.clipboard.readText().then(clipText?=>?document.querySelector(".editor").innerText?+=?clipText);
2.useClipboard
2.1簡介
useClipboard是響應式的剪貼板 API。提供剪貼板命令(剪切、復制和粘貼)以及異步讀取和寫入系統剪貼板的能力。訪問剪貼板內容需要獲得Permission API的相關權限,未經用戶許可則不允許讀取或更改剪貼板內容。
2.2例子
官方文檔的示例代碼如下所示:
<script?setup?lang="ts">
import?{?ref?}?from?'vue'
import?{?useClipboard,?usePermission?}?from?'@vueuse/core'const?input?=?ref('')const?{?text,?isSupported,?copy?}?=?useClipboard()
const?permissionRead?=?usePermission('clipboard-read')
const?permissionWrite?=?usePermission('clipboard-write')
</script><template><div?v-if="isSupported"><note>Clipboard?Permission:?read?<b>{{?permissionRead?}}</b>?|?write<b>{{?permissionWrite?}}</b></note><p>Current?copied:?<code>{{?text?||?'none'?}}</code></p><input?v-model="input"?type="text"><button?@click="copy(input)">Copy</button></div><p?v-else>Your?browser?does?not?support?Clipboard?API</p>
</template>
首先引入 useClipboard,從useClipboard中解構出text, isSupported, copy。text是當前從剪切板讀取到的文本,isSupported用于判斷當前瀏覽器是否支持剪切板API,copy是將文本寫入到剪切板的方法。usePermission用于獲取權限,使用其查看了clipboard-read和clipboard-write的權限,并將權限展示到頁面上。通過下圖可以看到讀取的權限是prompt也就是詢問,而寫入操作被授權了即granted。定義了響應式的變量input綁定到input標簽上,當用戶點擊按鈕時則調用copy()方法將input的內容寫入剪切板。初始時我們沒有向剪切板寫入內容,text是空字符串,所以頁面顯示當前拷貝內容為none:當用戶輸入'123'點擊copy按鈕后,text的值也就是從剪切板讀取到的文本變成了'123',所以頁面展示內容也變成了'123'
2.3源碼
這里我們只保留了核心邏輯的40多行代碼,您可以查看源碼 瀏覽全部代碼。
export?function?useClipboard(options:?ClipboardOptions<MaybeRef<string>?|?undefined>?=?{}):?ClipboardReturn<boolean>?{const?{navigator?=?defaultNavigator,read?=?false,source,copiedDuring?=?1500,}?=?optionsconst?events?=?['copy',?'cut']const?isSupported?=?Boolean(navigator?&&?'clipboard'?in?navigator)const?text?=?ref('')?//?與剪切板內容相對應的響應式值const?copied?=?ref(false)?//?是否拷貝完成const?timeout?=?useTimeoutFn(()?=>?copied.value?=?false,?copiedDuring)//?更新textfunction?updateText()?{navigator!.clipboard.readText().then((value)?=>?{text.value?=?value})}//?監聽拷貝和剪切事件if?(isSupported?&&?read)?{for?(const?event?of?events)useEventListener(event?as?WindowEventName,?updateText)}//?將響應式值value拷貝到textasync?function?copy(value?=?unref(source))?{if?(isSupported?&&?value?!=?null)?{await?navigator!.clipboard.writeText(value)text.value?=?valuecopied.value?=?truetimeout.start()}}return?{isSupported,text:?text?as?ComputedRef<string>,copied:?copied?as?ComputedRef<boolean>,copy,}
}
2.3.1參數
(1)navigator默認為window.navigator, 其定義如下:
export?const?defaultNavigator?=?/*?#__PURE__?*/?isClient???window.navigator?:?undefined
(2)read表示是否允許讀取剪切板的內容,默認值是false, 也就是默認不實時讀取剪切板的內容。我們通過例子的截圖知道默認clipboard-read的值是prompt即詢問,您可以通過瀏覽器的隱私設置來設置對于剪切板的權限:當調用useClipboard時指定了read為true, 并且你允許查看復制到剪切板中的數據,則此時只要剪切板里有內容就會實時顯示:
const?{?text,?isSupported,?copy?}?=?useClipboard({read:true})
上圖是選中了"Clipboard"這幾個字后右鍵點擊復制后系統彈出確認框。
上圖是點擊“允許”后復制到剪切板的內容實時賦值給了text并顯示在頁面中了。(3)source拷貝的源數據,可選的。source的原始值可以作為copy函數的默認值:
async?function?copy(value?=?unref(source))?{//省略}
如下圖所示當沒有指定source時的情況:可以看到value對應傳給copy的參數input, 而source是undefined。(4)copiedDuring為重置copied的毫秒數,copied用來表示是否拷貝完成。
2.3.2updateText
function?updateText()?{navigator!.clipboard.readText().then((value)?=>?{text.value?=?value})
}
updateText用于更新text的值,從剪切板中讀取數據然后更新text,讀取剪切板數據使用的是readText()方法。
2.3.3監聽拷貝和剪切
if?(isSupported?&&?read)?{for?(const?event?of?events)useEventListener(event?as?WindowEventName,?updateText)
}
在允許讀取剪切板的情況下,如果發生拷貝和剪切則用剪切板中的內容更新text。
2.3.4 copy方法
async?function?copy(value?=?unref(source))?{if?(isSupported?&&?value?!=?null)?{await?navigator!.clipboard.writeText(value)text.value?=?valuecopied.value?=?truetimeout.start()}
}
copy方法用于將參數value寫入剪切板并賦值給text,寫入剪切板使用的是writeText()方法。至此,useClipbord的源碼就分析完了,挺簡單的但是讀完也有收獲。
3.總結
本文介紹了原生的Clipboard API之后又介紹了useClipboard 的使用,然后結合示例代碼的調試過程分析了useClipboard 的源碼。Clipboard API中的readText()和 writeText()是useClipboard 的靈魂。
·················?若川簡介?·················
你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經堅持寫了8年,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助4000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。
掃碼加我微信 ruochuan12、拉你進源碼共讀群
今日話題
目前建有江西|湖南|湖北?籍 前端群,想進群的可以加我微信 ruochuan12?進群。分享、收藏、點贊、在看我的文章就是對我最大的支持