純JS實(shí)現(xiàn)監(jiān)控本地文件變化
網(wǎng)頁(yè)端的超級(jí)能力:File System Observer API
在最新的Web技術(shù)革命中,我們迎來(lái)了一個(gè)令人興奮的新API——File System Observer API(文件系統(tǒng)觀察者API)。這不僅僅是一個(gè)簡(jiǎn)單的文件操作工具,它賦予了網(wǎng)頁(yè)應(yīng)用前所未有的能力——實(shí)時(shí)監(jiān)控本地文件的一舉一動(dòng)!
實(shí)時(shí)監(jiān)控,無(wú)需刷新
想象一下,你正在開(kāi)發(fā)一個(gè)Web端相冊(cè)應(yīng)用,用戶可以隨時(shí)添加或刪除圖片。有了File System Observer API,你的應(yīng)用能夠即時(shí)響應(yīng)這些變化,無(wú)需用戶手動(dòng)刷新頁(yè)面。這就像是給網(wǎng)頁(yè)裝上了千里眼和順風(fēng)耳,任何文件的新增、修改或刪除都逃不過(guò)它的監(jiān)控。
實(shí)現(xiàn)監(jiān)聽(tīng),簡(jiǎn)單幾步
實(shí)現(xiàn)文件監(jiān)聽(tīng)的步驟簡(jiǎn)單到令人難以置信。首先,你需要實(shí)例化一個(gè)FileSystemObserver
對(duì)象,并傳入一個(gè)回調(diào)函數(shù)。然后,通過(guò)showOpenFilePicker
或showDirectoryPicker
選擇要監(jiān)聽(tīng)的文件或文件夾,并使用observe
方法開(kāi)始監(jiān)聽(tīng)。
監(jiān)聽(tīng)文件和文件夾
無(wú)論是單個(gè)文件還是整個(gè)文件夾,F(xiàn)ile System Observer API都能輕松應(yīng)對(duì)。你可以選擇監(jiān)聽(tīng)文件夾的一級(jí)內(nèi)容,或者通過(guò)設(shè)置recursive: true
來(lái)監(jiān)聽(tīng)所有子級(jí)內(nèi)容。
操作類型全覆蓋
文件的新建、刪除、修改、移動(dòng),甚至是重命名,F(xiàn)ile System Observer API都能準(zhǔn)確捕捉并通知你的應(yīng)用。每個(gè)操作都會(huì)生成一個(gè)詳細(xì)的FileSystemChangeRecord
對(duì)象,讓你能夠精確地了解發(fā)生了什么。
試一下我們的 Demo,實(shí)時(shí)進(jìn)行修改,就會(huì)觸發(fā)
解除監(jiān)聽(tīng),一鍵搞定
當(dāng)你想要停止監(jiān)聽(tīng)某個(gè)文件或文件夾時(shí),只需調(diào)用disconnect
方法,一切都會(huì)恢復(fù)原狀。
怎么申請(qǐng)token
首先我們?cè)L問(wèn) 谷歌FSO申請(qǐng)鏈接 并登錄賬號(hào)。
FSO 還是一套嶄新的 API,有多新呢?MDN 和 CanIUse 中還沒(méi)有建立關(guān)于它的詞條。但這并不意味著我們完全無(wú)法用于生產(chǎn)環(huán)境,我已經(jīng)用到線上功能中了。只要做一點(diǎn)配置工作,你和你的用戶就能成為全球第一批享受到 FSO 的人 。
Chrome 已經(jīng)對(duì) FSO 開(kāi)啟了試用,版本范圍是 129 到 134,你可以為你的 Web App 域名注冊(cè)一個(gè)試用 token,你可以跟著我一步一步操作
f12打開(kāi)控制臺(tái)輸入FileSystemObserver
,如果有返回既是使用成功
那怎么調(diào)用這套API來(lái)實(shí)現(xiàn)我們監(jiān)聽(tīng)文件夾的功能?
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>谷歌FSO API</title> <style> .row-box { display: flex; } .row-box > div { width: 50%; height: 70vh; overflow: auto; } #log-box { background-color: #f0f0f0; padding: 10px; border: 1px solid #ccc; border-radius: 5px; display: none; } .alert-box { color: red; font-size: 12px; line-height: 1; margin-bottom: 12px; padding: 8px; border-radius: 12px; } .alert-title,.alert-content{ font-size: 20px; } #dir-name{ color: red; } </style> </head> <body> <h1>File Observer API 監(jiān)聽(tīng)文件夾變化</h1> <div class="alert-box"> <div class="alert-title">?? 注意?。?!</div> <div class="alert-content"> <p>本程序不會(huì)上傳任何文件到服務(wù)器,切勿使用重要文件進(jìn)行調(diào)試,以免造成數(shù)據(jù)丟失</p> </div> </div> <button id="dir-btn">請(qǐng)選擇一個(gè)文件夾進(jìn)行監(jiān)聽(tīng)</button> <p> <span id="dir-name"></span> </p> <div class="row-box"> <div id="dir-info"></div> <div id="log-box"></div> </div> <script type="importmap"> { "imports": { "@rejax/fsot": "https://unpkg.com/@rejax/fsot/index.js" } } </script> <script type="module"> import { setFSObserverToken } from './index.js' setFSObserverToken() </script> <script type="module"> import { FSObserver } from '@rejax/fsot' const dirBtn = document.getElementById('dir-btn') const dirInfo = document.getElementById('dir-info') const logBox = document.getElementById('log-box') const dirName = document.getElementById('dir-name') let dirEntries = null const fob = new FSObserver(callback) const kindMap = { 'directory': '文件夾', 'file': '文件', } const operationMap = { 'appeared': '新增', 'disappeared': '刪除', 'modified': '修改', 'moved': '移動(dòng)', 'renamed': '重命名', } dirBtn.addEventListener('click', handleClick) async function handleClick() { const dirHandle = await window.showDirectoryPicker() dirEntries = dirHandle.values() const options = { recursive: true, } console.log('fob', fob); await fob.observe(dirHandle, options) const localDirName = fob.rootHandle.name dirName.innerText=`當(dāng)前監(jiān)聽(tīng)的本地目錄: ${localDirName}` dirBtn.disabled = true logBox.style.display = 'block' for await (const entry of dirEntries) { const { kind, name } = entry showChild(kind, name) } } async function callback(log, records, observer) { console.log('log', log); const logEle = document.createElement('p') logEle.innerText = log.description logBox.appendChild(logEle) const { operation, handle, to, from } = log switch (operation) { case 'create': add(handle, to) break case 'remove': remove(handle, to) break case 'modify': modifyFile(handle, to) break case 'move': move(handle, to, from) break case 'rename': rename(handle, to, from) break } } function showChild(kind, name) { const entryId = `${kind}-${name}` const entry = document.createElement('p') entry.id = entryId entry.innerHTML = `${kindMap[kind]} ${name}` dirInfo.appendChild(entry) } async function add(handle, path) { const { kind } = handle if (!path.includes('/')) { // 子文件中增加實(shí)體時(shí),不顯示 showChild(kind, path) } } function remove(handle, path) { const { kind, name } = handle const childName = path || name const entryId = `${kind}-${childName}` const entry = document.getElementById(entryId) if (entry) { entry.remove() } } async function modifyFile(handle, path) { } async function rename(handle, path, oldPath) { const { kind, name } = handle const childName = path || name const entryId = `${kind}-${oldPath}` let entry = document.getElementById(entryId) if (entry) { entry.innerText = `${kindMap[kind]} ${path}` entry.id = `${kind}-${path}` } } async function move(handle, path, oldPath) { const { kind, name } = handle const childName = path || name const entryId = `${kind}-${oldPath}` let entry = document.getElementById(entryId) const pathArr = path.split('/') const oldPathArr = oldPath.split('/') // 文件層級(jí)下沉 if (pathArr.length > oldPathArr.length) { entry?.remove() } // 文件層級(jí)上升 if (pathArr.length < oldPathArr.length && pathArr.length === 1) { showChild(kind, name) } } </script> </body> </html>
這里是setFSObserverToken,把前面申請(qǐng)到的token進(jìn)行替換即可,這里要配置好域名,域名不一樣會(huì)報(bào)錯(cuò),無(wú)法使用
export function setFSObserverToken () { let token = 'AvBwEvROC6H+jSr2r1nwgj0G0T8tOs2MnXT9GSFcHVXV2un4GQ/+9Sa2TfWbJGhUbZe5lyF+APSpjovP+NtNEQwAAABWeyJvcmlnaW4iOiJodHRwOi8vMTI3LjAuMC4xOjUzMTA1IiwiZmVhdHVyZSI6IkZpbGVTeXN0ZW1PYnNlcnZlciIsImV4cGlyeSI6MTc0NzE4MDc5OX' const origin = window.location.origin if (origin.includes('https://rejax.fun')) { token = 'AvBwEvROC6H+jSr2r1nwgj0G0T8tOs2MnXT9GSFcHVXV2un4GQ/+9Sa2TfWbJGhUbZe5lyF+APSpjovP+NtNEQwAAABWeyJvcmlnaW4iOiJodHRwOi8vMTI3LjAuMC4xOjUzMTA1IiwiZmVhdHVyZSI6IkZpbGVTeXN0ZW1PYnNlcnZlciIsImV4cGlyeSI6MTc0NzE4MDc5OX' } const meta = document.createElement('meta') meta.httpEquiv = 'origin-trial' meta.content = token document.head.appendChild(meta) }
總結(jié)
File System Observer API的引入,不僅僅是對(duì)Web開(kāi)發(fā)者的一次解放,更是對(duì)整個(gè)Web生態(tài)的巨大推動(dòng)。它讓W(xué)eb應(yīng)用更加強(qiáng)大,用戶體驗(yàn)更加流暢?,F(xiàn)在,是時(shí)候開(kāi)始探索這個(gè)全新的API,為你的Web應(yīng)用增添超級(jí)能力了!
到此這篇關(guān)于純JS實(shí)現(xiàn)監(jiān)控本地文件變化的文章就介紹到這了,更多相關(guān)JS監(jiān)控本地文件變化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解js根據(jù)百度地圖提供經(jīng)緯度計(jì)算兩點(diǎn)距離
這篇文章主要介紹了js根據(jù)百度地圖提供經(jīng)緯度計(jì)算兩點(diǎn)距離,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05JavaScript 驗(yàn)證瀏覽器是否支持javascript的方法小結(jié)
一些網(wǎng)站只有客戶端js的驗(yàn)證,這樣就給一些hacher一些可趁之機(jī)了,不信大家測(cè)試一些網(wǎng)站的注冊(cè)功能看看,有部分網(wǎng)站只有客戶端驗(yàn)證,我為了達(dá)到客戶端驗(yàn)證,先是判斷瀏覽器是否支持js,如果不支持,提示信息,然后屏蔽掉發(fā)送按鈕2009-05-05基于BootStrap Metronic開(kāi)發(fā)框架經(jīng)驗(yàn)小結(jié)【七】數(shù)據(jù)的導(dǎo)入、導(dǎo)出及附件的查看處理
在很多系統(tǒng)模塊里面,我們可能都需要進(jìn)行一定的數(shù)據(jù)交換處理,這樣可以很好的達(dá)到用戶操作體驗(yàn)感,接下來(lái)通過(guò)本文給大家介紹基于BootStrap Metronic開(kāi)發(fā)框架經(jīng)驗(yàn)小結(jié)【七】數(shù)據(jù)的導(dǎo)入、導(dǎo)出及附件的查看處理相關(guān)知識(shí),非常具有參考價(jià)值,感興趣的朋友一起學(xué)習(xí)吧2016-05-05淺談html轉(zhuǎn)義及防止javascript注入攻擊的方法
下面小編就為大家?guī)?lái)一篇淺談html轉(zhuǎn)義及防止javascript注入攻擊的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12async/await實(shí)現(xiàn)Promise.acll()簡(jiǎn)介
Promise.all() 方法接收一個(gè) promise 的 iterable 類型的輸入,并且只返回一個(gè)Promise實(shí)例,并且輸入的所有 promise 的 resolve 回調(diào)的結(jié)果是一個(gè)數(shù)組,這篇文章主要介紹了async/await實(shí)現(xiàn)Promise.acll()簡(jiǎn)介,需要的朋友可以參考下2022-11-11Postman參數(shù)化實(shí)現(xiàn)過(guò)程及原理解析
這篇文章主要介紹了Postman參數(shù)化實(shí)現(xiàn)過(guò)程及原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08