上一篇有給大家分享過使用vue3和electron快速搭建專案、建立多視窗/父子modal視窗的一些方法。今天繼續給大家分享一些vue3.x+electron11專案開發中的一些知識點/踩坑記錄,希望對你有幫助~~
1、vue3+electron實現QQ登入介面
<template> <div> <div class="ntMain__cont flex1 flexbox flex-col"> <div class="nt__lgregWrapper flex1 flexbox flex-col vui__drag"> <NavBar title=" " transparent fixed> <template #wbtn> <a class="wbtn" title="設定"><i class="iconfont icon-shezhi1"></i></a> </template> </NavBar> <template v-if="!isShowQrcode"> <div class="nt__lgregBox flex1"> <div class="banner"> <h2 class="tit">Vue3-Electron</h2> <img class="bg" src="@assets/img/skin/bg-banner.png" /> </div> <div class="slogan"> <div class="avatar"><img src="@assets/logo-white.png" /></div> </div> <div class="forms"> <form @submit.prevent="handleSubmit"> <ul class="clearfix"> <li class="flexbox flex-alignc"><input class="iptxt flex1" type="text" v-model="formObj.tel" placeholder="請輸入手機號" autocomplete="off" maxLength="11" /><em class="borLine"></em></li> <li class="flexbox flex-alignc"><input class="iptxt flex1" type="password" v-model="formObj.pwd" placeholder="請輸入密碼" autocomplete="off" /><em class="borLine"></em></li> </ul> <div class="btns"><button class="vui__btn vui__btn-primary btn__submit" type="submit">登入</button></div> <div class="lgregLink align-c clearfix"> <router-link class="navigator" to="#">忘記密碼</router-link> <router-link class="navigator" to="/register">註冊賬號</router-link> </div> </form> </div> </div> <div class="nt__lgregFoot vui__nodrag" @click="handleShowQR"> <i class="iconfont icon-saoma"></i> </div> </template> <template v-else> <div class="nt__lgregBox flex1"> <div class="banner"> <h2 class="tit">Vue3-Electron</h2> <img class="bg" src="@assets/img/skin/bg-banner.png" /> </div> <div class="slogan"> <div class="qrcode"><img src="@assets/img/placeholder/wx-qrcode.jpg" /></div> </div> <div class="forms"> <div style="text-align:center;margin:20px 0 25px;">使用手機掃一掃快速登入。</div> <div class="btns"><button class="vui__btn vui__btn-primary btn__submit" @click="handleShowQR">返回</button></div> </div> </div> </template> </div> </div> </div> </template> <script> import { ref, reactive, inject } from 'vue' import { useStore } from 'vuex' import { createWin } from '@module/actions' export default { components: {}, setup() { const store = useStore() const v3layer = inject('v3layer') const utils = inject('utils') const isShowQrcode = ref(false) const formObj = reactive({}) const handleShowQR = () => { isShowQrcode.value = !isShowQrcode.value } const VTips = (content) => { v3layer({content: content, time: 2}) } const handleSubmit = () => { if(!formObj.tel){ VTips('手機號不能為空!') }else if(!utils.checkTel(formObj.tel)){ VTips('手機號格式不正確!') }else if(!formObj.pwd){ VTips('密碼不能為空!') }else{ store.commit('SET_ISLOGIN', true); store.commit('SET_TOKEN', utils.setToken()); store.commit('SET_USER', formObj.tel); // ... } } return { isShowQrcode, handleShowQR, formObj, handleSubmit } } } </script>
全域性路由鉤子判斷登入狀態,沒有登入就跳轉到上面的登入頁面。
// 全域性鉤子攔截登入狀態 router.beforeEach((to, from, next) => { const hasLogined = store.state.isLogin // 判斷當前路由地址是否需要登入許可權 if(to.meta.requireAuth) { if(hasLogined) { next() }else { // 跳轉登入頁面 loginWin() } }else { next() } })
/** * @desc 登入視窗 */ export function loginWin() { createWin({ isMainWin: true, title: '登入', route: '/login', width: 430, height: 330, resize: false, alwaysOnTop: true, }) }
注意1:當自定義可拖拽區域,必須是兄弟節點或是父子節點,如果是通過position:absolute/fixed定位,則定位的那個區域設定 -webkit-app-region: no-drag 會無效/無法點選。這時需要把定位的元素放在可拖拽節點的子節點裡面。
如上圖:如果把NavBar元件放在箭頭位置,設定/最小化/關閉按鈕會無法點選。
<script> import { getCurrentInstance } from 'vue' export default { setup() { const { ctx } = getCurrentInstance() ctx.$store.commit(...) ctx.$router.push(...) } } </script>
注意2:最好不要使用上面的getCurrentInstance來獲取上下文操作,打包的時候會報錯+報錯+報錯。
2、vue3+electron實現無邊框窗體自定義導航條
建立窗體的時候,設定 frame: false 視窗會無頂部欄。這時就需要自定義拖拽區域和最小/大化及關閉按鈕了。
新建navbar.vue和winbar.vue兩個模板,分別是導航欄/右上角按鈕組。
- navbar模板
<template> <div class="nt__navbar" :class="{'fixed': fixed, 'transparent fixed': transparent}"> <div class="nt__navbar-wrap flexbox flex-alignc vui__drag" :style="{'background': bgcolor, 'color': color, 'z-index': zIndex}"> <!-- 標題 --> <div class="nt__navbar-title" :class="{'center': center}"> <template v-if="$slots.title"><slot name="title" /></template> <template v-else>{{title || winCfg.window.title}}</template> </div> </div> <WinBar :minimizable="minimizable" :maximizable="maximizable" :closable="closable"> <slot name="wbtn" /> </WinBar> </div> </template> <script> import { winCfg } from '@module/actions' export default { props: { // 標題 title: { type: String, default: '' }, // 標題顏色 color: { type: String, default: '#fff' }, // 背景顏色 bgcolor: String, // 標題是否居中 center: { type: [Boolean, String], default: false }, // 是否固定 fixed: { type: [Boolean, String], default: false }, // 背景透明 transparent: { type: [Boolean, String], default: false }, // 設定層級 zIndex: { type: [Number, String], default: '2021' }, /** * WinBar元件引數 */ // 視窗是否可以最小化 minimizable: { type: [Boolean, String], default: true }, // 視窗是否可以最大化 maximizable: { type: [Boolean, String], default: true }, // 視窗是否可以關閉 closable: { type: [Boolean, String], default: true }, }, setup() { return { winCfg, } } } </script>
支援自定義標題/居中、顏色/背景色、是否固定、透明背景等功能。
<NavBar bgcolor="#00d2ff" minimizable="false"> <template #title><i class="iconfont icon-about"></i> 關於</template> </NavBar>
<NavBar bgcolor="#15ff95" color="#f00" center> <template #title><i class="iconfont icon-huanfu"></i> 個性裝扮</template> <template #wbtn> <a class="wbtn" title="我的裝扮"><i class="iconfont icon-tabbar3"></i></a> </template> </NavBar>
<NavBar :bgcolor="headerBg" transparent> <template #title><i class="iconfont icon-pyq"></i> 朋友圈</template> <template #wbtn> <a class="wbtn" title="更換封面"><i class="iconfont icon-dianzan"></i></a> <a class="wbtn" title="釋出" @click="isShowPublish=true"><i class="iconfont icon-paizhao"></i></a> </template> </NavBar>
- winbar.vue模板
<template> <div class="vui__winbtn flexbox flex-alignc"> <div class="vui__winbtn-groups" :style="{'color': color}"> <slot /> <a v-if="JSON.parse(minimizable)" class="wbtn" title="最小化" @click="handleWinMin"><i class="iconfont icon-min"></i></a> <a v-if="JSON.parse(maximizable)&&winCfg.window.resize" class="wbtn" :title="hasMaximized ? '向下還原' : '最大化'" @click="handleWinMax2Min"><i class="iconfont" :class="hasMaximized ? 'icon-restore' : 'icon-max'"></i></a> <a v-if="JSON.parse(closable)" class="wbtn close" title="關閉" @click="handleWinClose"><i class="iconfont icon-quit"></i></a> </div> </div> </template> <script> import { remote } from 'electron' import { onMounted, reactive, inject, toRefs } from 'vue' import { useStore } from 'vuex' import { winCfg, setWin } from '@module/actions' export default { props: { color: { type: String, default: '#fff' }, // 視窗是否可以最小化 minimizable: { type: [Boolean, String], default: true }, // 視窗是否可以最大化 maximizable: { type: [Boolean, String], default: true }, // 視窗是否可以關閉 closable: { type: [Boolean, String], default: true }, }, setup() { let win = remote.getCurrentWindow() const store = useStore() const v3layer = inject('v3layer') const data = reactive({ hasMaximized: false }) onMounted(() => { if(win.isMaximized()) { data.hasMaximized = true } win.on('maximize', () => { data.hasMaximized = true }) win.on('unmaximize', () => { data.hasMaximized = false }) }) // 最小化 const handleWinMin = () => { setWin('min', winCfg.window.id) } // 最大化/還原 const handleWinMax2Min = () => { setWin('max2min', winCfg.window.id) } // 關閉 const handleWinClose = () => { setWin('close', winCfg.window.id) } return { ...toRefs(data), winCfg, handleWinMin, handleWinMax2Min, handleWinClose } } } </script>
支援自定義顏色、是否可以最大/小化及關閉等功能。
<!-- //網址連結模板 --> <template> <div> <NavBar></NavBar> <!-- 內容區 --> <div class="ntMain__cont flex1 flexbox flex-col"> <div class="vChat__lkview"> <iframe scrolling="auto" allowtransparency="true" frameborder="0" :src="data.url"></iframe> </div> </div> </div> </template>
<WinBar color="#ff0"> <a class="wbtn" title="關於" @click="handleAboutWin"><i class="iconfont icon-about"></i></a> <a class="wbtn" title="個性裝扮" @click="handleSkinWin"><i class="iconfont icon-huanfu"></i></a> <a class="wbtn" title="朋友圈" @click="handleFZoneWin"><i class="iconfont icon-pyq2"></i><em class="vui__badge-dot"></em></a> <a class="wbtn" title="設定" @click="isShowSettingLayer=true"><i class="iconfont icon-peizhi"></i></a> <a class="wbtn" title="介面管理器" @click="handleUIManager"><i class="iconfont icon-tianjia"></i></a> <a class="wbtn" :class="{'on': isAlwaysOnTop}" :title="isAlwaysOnTop ? '取消置頂' : '置頂'" @click="handleAlwaysTop"><i class="iconfont icon-ding"></i></a> </WinBar>
實現起來非常簡單,只是需要注意一些細節即可。另外設定-webkit-app-region: drag之後,下面的子元素記得要設定-webkit-app-region: no-drag,否則無法響應點選事件。
另外拖拽區域會出現如下系統右鍵選單,為了讓拖拽區更加逼真,需要遮蔽系統選單。
win.hookWindowMessage(278, function(e){ win.setEnabled(false) setTimeout(() => { win.setEnabled(true) }, 150) return true })
3、vue3+electron模仿QQ托盤圖示/托盤閃爍
在專案根目錄下放置兩個大小一致的tray.ico檔案,其中一個透明即可。
let tray = null let flashTimer = null let trayIco1 = path.join(__dirname, '../static/tray.ico') let trayIco2 = path.join(__dirname, '../static/tray-empty.ico') // 建立系統托盤圖示 createTray() { const trayMenu = Menu.buildFromTemplate([ { label: '我線上上', icon: path.join(__dirname, '../static/icon-online.png'), click: () => {...} }, { label: '忙碌', icon: path.join(__dirname, '../static/icon-busy.png'), click: () => {...} }, { label: '隱身', icon: path.join(__dirname, '../static/icon-invisible.png'), click: () => {...} }, { label: '離開', icon: path.join(__dirname, '../static/icon-offline.png'), click: () => {...} }, {type: 'separator'}, { label: '關閉所有聲音', click: () => {...}, }, { label: '關閉頭像閃動', click: () => { this.flashTray(false) } }, {type: 'separator'}, { label: '開啟主視窗', click: () => { // ... } }, { label: '退出', click: () => { // ... } }, ]) this.tray = new Tray(this.trayIco1) this.tray.setContextMenu(trayMenu) this.tray.setToolTip(app.name) this.tray.on('double-click', () => { // ... }) } // 托盤圖示閃爍 flashTray(flash) { let hasIco = false if(flash) { if(this.flashTimer) return this.flashTimer = setInterval(() => { this.tray.setImage(hasIco ? this.trayIco1 : this.trayIco2) hasIco = !hasIco }, 500) }else { if(this.flashTimer) { clearInterval(this.flashTimer) this.flashTimer = null } this.tray.setImage(this.trayIco1) } } // 銷燬托盤圖示 destoryTray() { this.flashTray(false) this.tray.destroy() this.tray = null }
呼叫 flashTray(true) 和 flashTray(false) 分別開啟/關閉托盤圖示閃爍。
在一開始除錯的時候托盤圖示一直不顯示,最後發現是路徑錯了。通過 console.log(__dirname) 指向了預設的 dist_electron 打包目錄。
console.log('----------開始建立托盤')
console.log(__dirname)
console.log(path.join(__dirname, '../static/tray.ico'))
4、vue3+electron打包遇到的一些坑
專案使用的是electron-builder打包器來打包的,下面是常用的一些electron-builder打包配置。這裡選擇的是在vue.config.js裡面配置。
/** * 專案配置檔案 */ const path = require('path') module.exports = { ... // webpack配置 chainWebpack: config => { ... }, pluginOptions: { electronBuilder: { nodeIntegration: true, // 專案打包引數配置 builderOptions: { "productName": "electron-qchat", //專案名稱 打包生成exe的字首名 "appId": "com.example.electronqchat", //包名 "compression": "maximum", //store|normal|maximum 打包壓縮情況(store速度較快) "artifactName": "${productName}-${version}-${platform}-${arch}.${ext}", // "directories": { // "output": "build", //輸出資料夾(預設dist_electron) // }, "asar": false, //asar打包 // 拷貝靜態資源目錄到指定位置 "extraResources": [ { "from": "./static", "to": "static" }, ], "nsis": { "oneClick": false, //一鍵安裝 "allowToChangeInstallationDirectory": true, //允許修改安裝目錄 "perMachine": true, //是否開啟安裝時許可權設定(此電腦或當前使用者) "artifactName": "${productName}-${version}-${platform}-${arch}-setup.${ext}", "deleteAppDataOnUninstall": true, //解除安裝時刪除資料 "createDesktopShortcut": true, //建立桌面圖示 "createStartMenuShortcut": true, //建立開始選單圖示 "shortcutName": "ElectronQChat", //桌面快捷鍵圖示名稱 }, "win": { "icon": "./static/shortcut.ico", //圖示路徑 } } } } }
1、大家如果在.vue頁面中使用 ipcRenderer 或 remote 模組,出現如下報錯:
Uncaught TypeError: fs.existsSync is not a function
出現這個問題的原因:
- 因為渲染程式屬於瀏覽器端,沒有整合Node的環境,像fs這樣的Node包是不可以使用的。
- 沒有Node環境,所以require關鍵詞也是不可以使用的。
配置如上引數即可快速解決問題。
2、專案路徑不能設定中文,否則打包會出錯,一定要養成英文命名習慣。
3、最好不要使用getCurrentInstance函式來獲取上下文,操作store或router,打包會出錯。
4、建立的vue3專案預設會是 createWebHistory 模式,打包會出現白屏情況;改為 createWebHashHistory Hash模式。
5、打包靜態資源缺失或截圖dll無效。需在打包配置裡設定 extraResources 引數。
"extraResources": [ { "from": "./static", "to": "static" }, ],
from參數列示資源目錄位置,to表示打包時移動資源目錄到指定位置。如下圖所示:
專案中的static目錄用來存放一些ico圖示或截圖dll檔案,即配置中的from目錄名稱。
打包後,會在resources目錄下生成static資料夾,即配置中的to定義的目錄名稱。
好了,以上就是vue3+electron11開發跨平臺專案的一些分享及踩坑記錄,希望能幫助到大家哈!
最後貼上一個vue3.0+vant3開發移動端h5聊天例項
https://www.cnblogs.com/xiaoyan2017/p/14250798.html