🧑💻 寫在開頭
點贊 + 收藏 === 學會🤣🤣🤣
前言: 最近接到了一個需求很有意思,類似於我們經常在逛購物平臺中,選擇一個物品分享給好友,然後好友複製這段文字開啟相對應的平臺以後,就可以彈出連結上的物品。實現過程也比較有意思,特來分享一下實現思路🎁。
一. 效果預覽
當我在別的介面複製了內容以後,回到主應用,要求可以檢測到當前剪下板是什麼內容。
二. 監聽頁面跳轉動作
-
要完成這個需求,整體思路並不複雜。首先我們要解決的就是如何檢測到使用者從別的應用切回到我們自己的應用。
-
這個聽起來很複雜,但其實瀏覽器已經提供了相對應的
api
來幫我們檢測使用者這個操作----document.visibilitychange
。
- 那麼我們就可以寫下如下程式碼
document.addEventListener("visibilitychange", () => { console.log("使用者切換了"); });
-
這也不難理解,首先你要理解這個
change
這個動作,你從 tab1 切換到 Tab2 的時候,觸發了當前 Tab1 從可見 變為=> 不可見 。
而當你從 tab2 切回 tab1 的時候,觸發了當前 Tab1 從不可見變為了可見。完整動作引起了狀態兩次變化,所以才有了兩次列印。 -
而我們的場景只是希望 app 從不可見轉變為可見的時候才觸發。那麼我們就需要用到另外一個變數來配合使用-------
document.visibilityState
。
-
這個值是一個
document
物件上的一個只讀屬性,它有三個string
型別的值visible
、hidden
、prerender
。從它的使用說明中不難看出,我們要使用的值是visible
。tips:hidden 可以用來配合做一些流量控制最佳化,當使用者切換網頁到後臺的時候,我們可以停止一些不必要的輪詢任務,待使用者切回後再開啟。
-
那麼我們現在的程式碼應該是這樣的:
document.addEventListener("visibilitychange", () => { if (document.visibilityState === "visible") { console.log("頁面變得可見了!"); } });
三. 完成讀取剪下板內容
-
要完成讀取剪下板內容需要用到瀏覽器提供的另外一個
api
-----navigator.clipboard
。這裡穿插一個英語記憶的小技巧,我們要把這個單詞分成兩部分記憶:clip 和 board。clip 本身就有修剪的意思,board 常作為木板相近的含義和別的單片語合,如:黑板 blackboard、棋盤 chessboard。所以這兩個單片語合起來的含義就是剪下板。
- 這裡需要注意一句話,這個功能只能用在安全上下文中。這個概念很抽象,如果想深入瞭解的話,還需自行查閱資料。這裡指簡單說明這句話的限制:要想使用這個
api
你只能在localhost、127.0.0.1
這樣的本地迴環地址或者使用https
協議的網站中使用。
-
要快速檢測當前瀏覽器或者網站是否是安全上下文 ,可以使用
Window:isSecureContext
屬性來判斷。 -
你可以動手訪問一個 http 的網站,然後在控制檯列印一下該屬性,你大機率會看到一個
false
,則說明該環境不是一個安全上下文,所以 clipboard 在這個環境下大機率不會生效。因為本文章程式碼都為本地開發(localhost),所以自然為安全上下文。
- 經過上面的知識,那麼我們就可以寫出下面的相容性程式碼。
-
前置步驟都已經完成,接下來就是具體讀取剪下板內容了。關於讀取操作,
clipboard
提供了兩個api
-----read
和readText
。這裡由於我們的需求很明確,我讀取的連結本身就是一個字串型別的資料,所以我們就直接選用readText
方法即可。稍後在第四章節我會介紹read
方法。 -
clipboard
所有操作都是非同步會返回一個Promise
型別的資料的,所以這裡我們的程式碼應該是這樣的:
document.addEventListener("visibilitychange", () => { if (document.visibilityState === "visible") { if (window.isSecureContext && navigator.clipboard) { const clipboardAPI = navigator.clipboard; //獲取 clipboard 物件 setTimeout(() => { clipboardAPI.readText().then((text) => { console.log("text", text); }); }, 1000); } else { console.log("不支援 clipboard"); } } });
setTimeout
來解決演示的問題,如果你正在跟著練習但是不明白原因,請檢視下面連結:關於 DOM exception: document is not focused 請查閱stackoverflow 文件未聚焦的解決方案
- 此時,當拿到使用者剪下板的內容以後,我們就可以根據某些特點來判斷彈窗了。這裡我隨便使用了一個彈出元件來展示效果:
- 什麼?到這裡你還是沒看懂和網購平臺連結之間有什麼關係?ok,讓我們仔細看一下我分別從兩家平臺隨手複製的兩個連結,看出區別了嗎?開頭的字串可以很明顯看出是各家的名字。
- 那麼我只需判斷使用者剪下板上的字串是否符合站內的某項規則不就行了嗎?讓我來舉個更具體的栗子,下面連結是我掘金的個人首頁,假如使用者此時複製了這段文字,然後跳轉回我們自己的應用後,剛剛的程式碼就可以加一個邏輯判斷,檢測使用者剪下板上的連結是否是以
juejin.cn
開頭的,如果是則跳轉首頁;如果不是,那麼什麼事情也不做。
對應的程式碼如下:
- 那麼相對應的效果如下,這也就是為什麼複製某寶的連結到某東後沒任何反應的原因。某東並不是沒讀取,而是讀取後發現不是自家的就不處理罷了
四*. 思維擴充:貼上圖片自動轉連結的實現
-
用過相關寫作平臺的小夥伴大概對在編輯器中直接接貼上圖片的功能不陌生。如掘金的編輯器,當我複製一個圖片以後,直接在編輯器中貼上即可。掘金會自動將圖片轉換為一個連結,這樣會極大的提高創作者的寫作體驗。
- 那麼現在讓我們繼續發散思維來思考這個需求如何實現,這裡我們先隨便建立一個富文字框。
- 既然是貼上圖片,那麼最起碼我得知道使用者什麼時候進行貼上操作吧?這還不簡單,直接監聽
paste
事件即可。
document.addEventListener("paste",()=>{ console.log("使用者貼上了") })
- 把之前的
clipboard.readText
替換為clipboard.read
以後你的程式碼應該是下面這樣的:
document.addEventListener("paste", () => { if (window.isSecureContext && navigator.clipboard) { const clipboardAPI = navigator.clipboard; //獲取 clipboard 物件 setTimeout(() => { clipboardAPI.read().then((result) => { console.log("result", result); }); }, 1000); } else { console.log("不支援 clipboard"); } });
-
clipboardItem
是一個陣列,裡面有很多子clipboardItem
,是陣列的原因是因為你可以一下子複製多張圖片,不過在這裡我們只考慮一張圖片的場景。 -
這裡我們取第一項,然後呼叫
clipboardItem.getType
方法,這個方法需要傳遞一個檔案型別的引數,這裡我們傳入貼上內容對應的型別即可,這裡傳入image/png
。
在控制檯這裡可以看到一下輸出,就表示我們已經正確拿到圖片的 blob
的格式資料了。
- 此時我們就只需要把相對應的圖片資料傳遞給後端或者
CDN
伺服器,讓它們返回一個與之對應的連結即可。在掘金的編輯器中,對應的請求就是get-image-url
這個請求。
-
然後呼叫
textarea.value + link
把連結補充到文章最後位置即可。
五. 原始碼
<script lang="ts" setup> document.addEventListener("visibilitychange", () => { if (document.visibilityState === "visible") { if (window.isSecureContext && navigator.clipboard) { const clipboardAPI = navigator.clipboard; //獲取 clipboard 物件 setTimeout(() => { clipboardAPI.read().then((result) => {}); }, 1000); } else { console.log("不支援 clipboard"); } } }); document.addEventListener("paste", () => { if (window.isSecureContext && navigator.clipboard) { const clipboardAPI = navigator.clipboard; //獲取 clipboard 物件 setTimeout(() => { clipboardAPI.read().then((result) => { result[0].getType("image/png").then((blob) => { console.log("blob", blob); const reader = new FileReader(); reader.readAsDataURL(blob); reader.onload = (e) => { const img = document.createElement("img"); img.src = e.target?.result; const wrapper = document.getElementById("han"); wrapper.appendChild(img); }; }); }); }, 1000); } else { console.log("不支援 clipboard"); } }); </script> <template> <div id="han" class="w-full h-full bg-blue"> <textarea class="w-300px h-300px"></textarea> </div> </template>
六. 思考 writeText 的用法
有了上面的經驗,我相信你已經可以自己理解 clipboard
剩下的兩個方法 write
和 writeText
了。你可以思考下面的問題:
為什麼在掘金複製文章內容後,剪下板會自動加版權資訊呢?。
如果你實現了,不妨在評論區寫下你的思路~🌹
本文轉載於:https://juejin.cn/post/7385776238789181449
如果對您有所幫助,歡迎您點個關注,我會定時更新技術文件,大家一起討論學習,一起進步。