效果展示 項目背景: 由於瀏覽器的限制,web批量下載體驗不好以及無法下載文件夾。採用Electron技術,通過js開發PC應用程式,著力解決批量下載、斷點續傳、文件夾下載等問題。配合網頁版網盤使用,單個小文件使用瀏覽器內置下載,單個大文件、多文件、文件夾調用PC應用程式,提升下載體驗。 技術棧 E ...
效果展示
項目背景:
由於瀏覽器的限制,web批量下載體驗不好以及無法下載文件夾。採用Electron技術,通過js開發PC應用程式,著力解決批量下載、斷點續傳、文件夾下載等問題。配合網頁版網盤使用,單個小文件使用瀏覽器內置下載,單個大文件、多文件、文件夾調用PC應用程式,提升下載體驗。
技術棧
Electron項目的目的,是為了要避免使用 vue 手動建立起 electron 應用程式。electron-vue 充分利用 vue-cli
作為腳手架工具,加上擁有 vue-loader
的 webpack
、electron-packager
或是 electron-builder
,以及一些最常用的插件,如vue-router
、vuex
等等。
技術點分析
1、web、PC應用程式通信
官方描述:
app.setAsDefaultProtocolClient(protocol[, path, args])
protocol
String - 協議的名稱, 不包含://
。 如果您希望應用程式處理electron://
的鏈接, 請將electron
作為該方法的參數.path
String (可選) Windows -預設為process.execPath
args
String[] (可選) Windows - 預設為空數組
返回 Boolean
-是否成功調用。
此方法將當前可執行文件設置為協議(也稱為URI方案) 的預設處理程式。 它允許您將應用程式更深入地集成到操作系統中。 一旦註冊成功, 所有 your-protocol://
格式的鏈接都會使用你的程式打開。 整個鏈接 (包括協議) 將作為參數傳遞給您的應用程式。
在 Windows 系統中,你可以提供可選參數 path,可執行文件的路徑和 args (在啟動時傳遞給可執行文件的參數數組)
註意: 在 macOS 上, 您只能註冊已添加到應用程式的 info. plist
中的協議, 在運行時不能對其進行修改。 但是,您可以在構建時使用簡單的文本編輯器或腳本更改文件。 有關詳細信息,請參閱 Apple's documentation
API 在內部使用 Windows 註冊表和 LSSetDefaultHandlerForURLScheme。
獲取參數:
主要分為兩個階段:一是初次啟動應用,而是應用已啟動打開鏈接時。
階段一:
webContents渲染以及控制web頁面,是BrowserWindow對象的一個屬性。
Event:'did-finish-load'
導航完成時觸發,即選項卡的旋轉器將停止旋轉,並指派 onload
事件後。
contents.on('did-finish-load', () => { getPath().then(dir => { setDir(dir) fileList("DOWN_FILE_LIST_FLAG__804e62a93de9fda85bb6ca68b20d3d6d") if(macOpenUrl != ''){//macOS fileList(macOpenUrl) }else{ try { let str = process.argv.slice(1)[0].split('//')[1] let downloadFlag = str.slice(0, str.length - 1) fileList(downloadFlag) } catch (e) { console.log(e) } } let httpList = deepList('.cfg') contents.send('download', httpList) }) })
階段二:
應用已啟動時,用戶打開URL。macOS有直接可捕捉的事件,Windows需要通過單實例的方法捕捉參數。
事件: 'open-url' macOS
返回:
event
Eventurl
String
當用戶想要在應用中打開一個 URL 時發出。 應用程式的 Info. plist
文件必須在 CFBundleURLTypes
項中定義 url 方案, 並將 NSPrincipalClass
設置為 AtomApplication
。
如果你想處理這個事件,你應該調用 event.preventDefault()
。
app.on("open-url", function(event, url) { //macOS:先進入open-url,再進入did-finish-load let downloadFlag = url.split('//')[1] macOpenUrl = downloadFlag if (mainWindow) { if (mainWindow.isMinimized()) mainWindow.restore() mainWindow.focus() try { fileList(downloadFlag) } catch (e) { console.log(e) } } })
app.makeSingleInstance()
返回 Boolean
此方法使應用程式成為單個實例應用程式, 而不是允許應用程式的多個實例運行, 這將確保只有一個應用程式的實例正在運行, 其餘的實例全部會被終止並退出。
const shouldQuit = app.makeSingleInstance((commandLine, workingDirectory) => { // Someone tried to run a second instance, we should focus our window. if (mainWindow) { if (mainWindow.isMinimized()) mainWindow.restore() mainWindow.focus() try { //dialog.showErrorBox('makeSingleInstance', commandLine.toString()) let str = commandLine.slice(1)[0].split('//')[1] let downloadFlag = str.slice(0, str.length - 1) fileList(downloadFlag) } catch (e) { console.log(e) } } })
URL長度限制問題:
基於項目背景,web、PC應用程式需要傳遞文件列表。一開始的想法是整個文件列表通過URL傳遞,後來調試的時候發現:受限於URL的長度限制,可以傳遞的文件項十分有限。於是另尋他路,通過後臺中轉:web選中文件後,調用後臺介面,生成下載標識位,傳遞給PC應用程式。PC應用程式那邊獲取到下載標識位後,通過下載標識位再請求後臺介面獲取下載列表。
2、文件重命名演算法
文件名的完整含義是文件的完整路徑,如:D:/tmp/新建文件夾/002.docx。文件重命名有兩個場景:一是當前的文件列表內,如果存在同名的文件,需要對當前的文件重命名,演算法同windows文件重命名演算法。二是文件保存到本地路徑時,如果當前路徑存在同名的文件,需要對當前的文件重命名,演算法同windows文件重命名演算法。
方法:fireRename(arr, basename, key)
- arr Arrary - 文件列表
basename
String 當前文件的文件名- key String(可選) 文件列表內每個對象文件名的關鍵字
文件重命名,返回重命名後的文件名。
const fileRename = (arr, basename, key) => { let existed arr.forEach((e, i) => { if (e[key] == basename) { existed = true } }) if (!existed) { return basename } let extname = path.extname(basename) let re = new RegExp('(\\(\\d\\))*' + extname + '$') const compare = (c, b) => { return c.replace(re, '') == b.replace(re, '') } let arr_existed = [] arr.forEach((e, i) => { let c = e[key] if (compare(c, basename)) { arr_existed.push(e[key].replace(c.replace(re, ''), '')) } }) for (let i = 1; i < arr_existed.length + 2; i += 1) { if (arr_existed.indexOf('(' + i + ')' + extname) == -1) { return basename.replace(re, '(' + i + ')' + extname) } } }