美國(guó)室內(nèi)設(shè)計(jì)聯(lián)盟優(yōu)化步驟
在普通的網(wǎng)頁開發(fā)中,JavaScript由于安全性的考慮,通常是無法直接獲取到客戶端的磁盤路徑的。瀏覽器出于隱私和安全原因?qū)Υ祟愋畔⑦M(jìn)行了限制。
在瀏覽器環(huán)境下,JavaScript主要通過Web APIs來與瀏覽器進(jìn)行交互,而這些API通常受到瀏覽器的安全策略的限制。文件系統(tǒng)信息是被認(rèn)為是敏感的信息,因此瀏覽器不提供直接訪問客戶端磁盤路徑的API。所以要使用electron屬性來獲取。
第一步:
electron分為主進(jìn)程和渲染進(jìn)程,主進(jìn)程就是使用electron的特性屬性api,渲染進(jìn)程就是我們的代碼,比如vue頁面代碼這種。
首先我們要把項(xiàng)目用electron啟動(dòng)起來,具體怎么啟動(dòng)看我上一篇博客
啟動(dòng)完成后,找到項(xiàng)目文件中的backgroun.js文件,這是electron主進(jìn)程的文件
把以下代碼加進(jìn)去
import { app, protocol, BrowserWindow ,ipcMain,ipcRenderer,dialog} from 'electron'
const fs = require('fs');
app.on('ready', async () => {// if (isDevelopment && !process.env.IS_TEST) {// // Install Vue Devtools// try {// await installExtension(VUEJS_DEVTOOLS)// } catch (e) {// console.error('Vue Devtools failed to install:', e.toString())// }// }createWindow()// 新增:在主進(jìn)程中處理打開保存圖片對(duì)話框的請(qǐng)求ipcMain.handle('dialog:saveImage', async (event, dataURL) => {return saveImage(dataURL);});
})// 將保存圖片的邏輯封裝成一個(gè)函數(shù)
async function saveImage(dataURL) {let base64 = dataURL.replace(/^data:image\/\w+;base64,/, '');let dataBuffer = Buffer.from(base64, 'base64');const options = {title: 'Save Image',buttonLabel: '保存', // 自定義保存按鈕的文字defaultPath: 'image.jpg', // 默認(rèn)文件名filters: [{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }]};const { canceled, filePath } = await dialog.showSaveDialog(options);if (canceled) {return null; // 用戶取消保存文件時(shí)返回 null} else {// 將 dataURL 保存到 filePath 的邏輯代碼fs.writeFile(filePath, dataBuffer, function (err) {if (err) {console.error(err, '保存失敗');} else {console.log(filePath, '保存成功');}});return filePath; // 返回用戶選擇的文件路徑}
}
- 在 Electron 應(yīng)用程序啟動(dòng)后,創(chuàng)建了窗口(
createWindow
函數(shù)應(yīng)該是在代碼中其他位置定義的)。 - 通過?
ipcMain.handle
?方法,為名為 'dialog:saveImage' 的事件注冊(cè)了一個(gè)處理函數(shù),用于處理保存圖片對(duì)話框的請(qǐng)求。當(dāng)渲染進(jìn)程發(fā)送 'dialog:saveImage' 事件時(shí),主進(jìn)程將會(huì)執(zhí)行?saveImage
?函數(shù)。 saveImage
?函數(shù)封裝了保存圖片的邏輯。首先將 Data URL 轉(zhuǎn)換為 Buffer 格式,然后通過?dialog.showSaveDialog
?方法展示保存對(duì)話框,用戶選擇保存路徑后,將圖片文件保存到指定路徑。-
在
saveImage
函數(shù)中: - 首先通過?
dataURL.replace
?和?Buffer.from
?將 Data URL 轉(zhuǎn)換成了 Buffer 格式。 - 然后使用?
dialog.showSaveDialog
?方法展示保存對(duì)話框,用戶選擇保存路徑后,通過?fs.writeFile
?方法將 Buffer 寫入文件。 - 最后根據(jù)保存成功或失敗,返回相應(yīng)的結(jié)果給渲染進(jìn)程。
fs
是 Node.js 核心模塊中的一個(gè)模塊,全稱為 File System(文件系統(tǒng))。這個(gè)模塊提供了一系列用于處理文件和文件系統(tǒng)的方法,可以用于讀取文件、寫入文件、創(chuàng)建目錄、刪除文件等操作。通過 fs
模塊,你可以在 Node.js 程序中對(duì)文件和文件系統(tǒng)進(jìn)行各種操作,包括讀寫文件、文件夾的操作等。
在 Electron 應(yīng)用程序中,由于可以利用 Node.js 的能力,因此可以在主進(jìn)程中使用 fs
模塊來處理文件和文件系統(tǒng)相關(guān)的操作,比如在上面的代碼中就使用了 fs.writeFile
方法來將圖片保存到指定路徑。
這是最終background.js文件的代碼:
'use strict'import { app, protocol, BrowserWindow ,ipcMain,ipcRenderer,dialog} from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
// import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
const isDevelopment = process.env.NODE_ENV !== 'production'
const fs = require('fs');// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([{ scheme: 'app', privileges: { secure: true, standard: true } }
])async function createWindow() {// Create the browser window.const win = new BrowserWindow({width: 800,height: 600,webPreferences: {// Use pluginOptions.nodeIntegration, leave this alone// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more infonodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION}})win.maximize()if (process.env.WEBPACK_DEV_SERVER_URL) {// Load the url of the dev server if in development modeawait win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)if (!process.env.IS_TEST) win.webContents.openDevTools()} else {createProtocol('app')// Load the index.html when not in developmentwin.loadURL('app://./index.html')}
}// Quit when all windows are closed.
app.on('window-all-closed', () => {// On macOS it is common for applications and their menu bar// to stay active until the user quits explicitly with Cmd + Qif (process.platform !== 'darwin') {app.quit()}
})app.on('activate', () => {// On macOS it's common to re-create a window in the app when the// dock icon is clicked and there are no other windows open.if (BrowserWindow.getAllWindows().length === 0) createWindow()
})// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {// if (isDevelopment && !process.env.IS_TEST) {// // Install Vue Devtools// try {// await installExtension(VUEJS_DEVTOOLS)// } catch (e) {// console.error('Vue Devtools failed to install:', e.toString())// }// }createWindow()// 新增:在主進(jìn)程中處理打開保存圖片對(duì)話框的請(qǐng)求ipcMain.handle('dialog:saveImage', async (event, dataURL) => {return saveImage(dataURL);});
})// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {if (process.platform === 'win32') {process.on('message', (data) => {if (data === 'graceful-exit') {app.quit()}})} else {process.on('SIGTERM', () => {app.quit()})}
}// 將保存圖片的邏輯封裝成一個(gè)函數(shù)
async function saveImage(dataURL) {let base64 = dataURL.replace(/^data:image\/\w+;base64,/, '');let dataBuffer = Buffer.from(base64, 'base64');const options = {title: 'Save Image',buttonLabel: '保存', // 自定義保存按鈕的文字defaultPath: 'image.jpg', // 默認(rèn)文件名filters: [{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }]};const { canceled, filePath } = await dialog.showSaveDialog(options);if (canceled) {return null; // 用戶取消保存文件時(shí)返回 null} else {// 將 dataURL 保存到 filePath 的邏輯代碼fs.writeFile(filePath, dataBuffer, function (err) {if (err) {console.error(err, '保存失敗');} else {console.log(filePath, '保存成功');}});return filePath; // 返回用戶選擇的文件路徑}
}
第二步:
去渲染進(jìn)程里寫相關(guān)代碼,也就是你的.vue文件
//保存畫布圖片saveCanvasBackground() {if (this.image.url == '') return// 獲取 canvas 元素和 Fabric 對(duì)象const canvas = document.getElementById("label-canvas");const fabricObj = this.fabricObj;// 將 canvas 內(nèi)容保存為圖片數(shù)據(jù) URLconst dataURL = canvas.toDataURL({format: "png", // 保存的圖片格式quality: 0.8, // 圖片質(zhì)量});//想主進(jìn)程發(fā)送打開保存圖片選項(xiàng)框請(qǐng)求ipcRenderer.invoke('dialog:saveImage', dataURL).then(response => {console.log(response, 'sssss');if (response) {// 接口// setsaveImage({// img:response// }).then(res=>{// console.log(res,'保存成功接口');// }).catch(err=>{// console.log(err,'保存失敗接口');// })} else {//用戶取消}}).catch(err => {console.error(err);});// 創(chuàng)建一個(gè) Blob 對(duì)象// const byteCharacters = atob(dataURL.split(",")[1]);// const byteNumbers = new Array(byteCharacters.length);// for (let i = 0; i < byteCharacters.length; i++) {// byteNumbers[i] = byteCharacters.charCodeAt(i);// }// const byteArray = new Uint8Array(byteNumbers);// const blob = new Blob([byteArray], { type: "image/png" });// // 創(chuàng)建一個(gè)下載鏈接// const url = URL.createObjectURL(blob);// // 創(chuàng)建一個(gè)下載按鈕并觸發(fā)點(diǎn)擊// const a = document.createElement("a");// a.style.display = "none";// a.href = url;// a.download = "saved_image.png"; // 設(shè)置下載的文件名// document.body.appendChild(a);// a.click();// // 釋放對(duì)象 URL,避免內(nèi)存泄漏// window.URL.revokeObjectURL(url);},
這段代碼是在渲染進(jìn)程中使用 ipcRenderer.invoke
方法向主進(jìn)程發(fā)送了一個(gè)名為 'dialog:saveImage' 的請(qǐng)求,同時(shí)傳遞了一個(gè)名為 dataURL
的參數(shù)。當(dāng)主進(jìn)程處理完這個(gè)請(qǐng)求后,渲染進(jìn)程會(huì)接收到相應(yīng)的結(jié)果。
在這段代碼中,使用了 ipcRenderer.invoke
方法來發(fā)送請(qǐng)求,并通過 Promise 對(duì)象處理響應(yīng)。如果主進(jìn)程成功處理了請(qǐng)求并返回了結(jié)果,會(huì)執(zhí)行 then
中的代碼,如果出現(xiàn)錯(cuò)誤,會(huì)執(zhí)行 catch
中的代碼。
在 then
中的代碼中,首先會(huì)打印出返回的 response
,然后根據(jù)返回的結(jié)果進(jìn)行相應(yīng)的處理。如果 response
存在,表示圖片保存成功,可以處理接口請(qǐng)求或其他邏輯;如果 response
不存在,表示用戶取消了保存操作,可以做出相應(yīng)的反應(yīng)。
整體來說,這段代碼的作用是在渲染進(jìn)程中向主進(jìn)程發(fā)送保存圖片選項(xiàng)框的請(qǐng)求,并根據(jù)主進(jìn)程返回的結(jié)果進(jìn)行相應(yīng)的處理。
以上紅色框內(nèi)就是運(yùn)行過后獲取出來當(dāng)前保存圖片的磁盤路徑!
雙擊點(diǎn)贊!!!!?