electron-vite【实战】登录/注册页
效果预览
项目搭建
https://blog.csdn.net/weixin_41192489/article/details/144611858
技术要点
路由默认跳转到登录页
src/renderer/src/router/index.ts
routes: [
// 默认跳转到登录页
{
path: '/',
redirect: '/login'
},
...routes
]
登录窗口的必要配置
src/main/index.ts 中
const mainWindow = new BrowserWindow({
// 自定义图标
icon: icon,
// 自定义窗口宽度
width: 360,
// 自定义窗口高度
height: 430,
//默认隐藏窗口
show: false,
// 隐藏窗口标题栏
titleBarStyle: 'hidden',
// 隐藏默认菜单
autoHideMenuBar: true,
// 不可改变窗口大小
resizable: false,
// 窗口不可最大化
maximizable: false,
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false
}
})
右上角关闭按钮的实现
src/renderer/src/pages/login.vue
<div class="text-right">
<el-icon
class="el-icon-edit text-20px hover:bg-red hover:text-white cursor-pointer p-2"
@click="quit"
><Close
/></el-icon>
</div>
渲染进程向主进程发送信息
function quit() {
window.electron.ipcRenderer.send('quit')
}
src/main/index.ts 主进程响应信息
ipcMain.on('quit', () => {
app.quit()
})
代码实现
src/renderer/src/router/index.ts
import { createRouter, createWebHashHistory } from 'vue-router'
import { routes, handleHotUpdate } from 'vue-router/auto-routes'
export const router = createRouter({
// 此处需用 Hash 模式,否则打包后路由会失效
history: createWebHashHistory(import.meta.env.BASE_URL),
routes: [
// 默认跳转到登录页
{
path: '/',
redirect: '/login'
},
...routes
]
})
// 支持热更新
if (import.meta.hot) {
handleHotUpdate(router)
}
src/main/index.ts
import { app, shell, BrowserWindow, ipcMain, Tray, Menu } from 'electron'
import { join } from 'path'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset'
function createWindow(): void {
const mainWindow = new BrowserWindow({
// 自定义图标
icon: icon,
// 自定义窗口宽度
width: 360,
// 自定义窗口高度
height: 430,
//默认隐藏窗口
show: false,
// 隐藏窗口标题栏
titleBarStyle: 'hidden',
// 隐藏默认菜单
autoHideMenuBar: true,
// 不可改变窗口大小
resizable: false,
// 不可改变窗口大小
maximizable: false,
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false
}
})
// 托盘
const tray = new Tray(icon)
const contextMenu = [
{
label: '退出',
click: function () {
app.exit()
}
}
]
const menu = Menu.buildFromTemplate(contextMenu)
tray.setToolTip('EC编程俱乐部')
tray.setContextMenu(menu)
tray.on('click', () => {
// 使窗口显示在任务栏中
mainWindow.setSkipTaskbar(false)
mainWindow.show()
})
// IPC通信
ipcMain.on('showPage_home', () => {
// 窗口可调整大小
mainWindow.setResizable(true)
mainWindow.setSize(800, 680)
// 窗口居中
mainWindow.center()
// 窗口可最大化
mainWindow.setMaximizable(true)
})
ipcMain.on('top', () => {
mainWindow.setAlwaysOnTop(true)
})
ipcMain.on('cancle_top', () => {
mainWindow.setAlwaysOnTop(false)
})
ipcMain.on('hide', () => {
// 使窗口不显示在任务栏中
mainWindow.setSkipTaskbar(true)
mainWindow.hide()
})
ipcMain.on('min', () => {
mainWindow.minimize()
})
ipcMain.on('max', () => {
mainWindow.maximize()
})
ipcMain.on('cancel_max', () => {
mainWindow.unmaximize()
})
mainWindow.on('ready-to-show', () => {
// 自定义标题
mainWindow.setTitle('EC编程俱乐部')
mainWindow.show()
})
// 窗口变为最大化状态
mainWindow.on('maximize', () => {
mainWindow.webContents.send('maximize')
})
// 窗口从最大化状态退出
mainWindow.on('unmaximize', () => {
mainWindow.webContents.send('unmaximize')
})
mainWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url)
return { action: 'deny' }
})
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
} else {
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
}
}
app.whenReady().then(() => {
// Set app user model id for windows
electronApp.setAppUserModelId('com.electron')
app.on('browser-window-created', (_, window) => {
optimizer.watchWindowShortcuts(window)
})
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
ipcMain.on('quit', () => {
app.quit()
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
src/renderer/src/pages/login.vue
仅前端页面渲染,省略了表单校验和后端交互。
<script setup lang="ts">
const form = reactive({ account: '', password: '', remember: false, passwordConfirm: '' })
const loginWay_list = [
{ icon: 'mdi:wechat', color: '#07cd66' },
{ icon: 'flat-color-icons:phone-android' },
{ icon: 'icon-park:tencent-qq' }
]
const PageType = ref('login')
function goToRegister() {
PageType.value = 'register'
}
function goToLogin() {
PageType.value = 'login'
}
const router = useRouter()
function submit_login() {
window.electron.ipcRenderer.send('showPage_home')
router.push('/home')
}
function quit() {
window.electron.ipcRenderer.send('quit')
}
</script>
<template>
<div class="text-right">
<el-icon
class="el-icon-edit text-20px hover:bg-red hover:text-white cursor-pointer p-2"
@click="quit"
><Close
/></el-icon>
</div>
<div class="w-360px bg-white p-8 pt-2 box-border overflow-hidden">
<div class="text-28px font-bold text-center p-6">
{{ PageType === 'login' ? 'EC 编程俱乐部' : '注册 EC' }}
</div>
<!-- 表单 -->
<el-form :model="form">
<el-form-item>
<el-input v-model="form.account" placeholder="请输入账号">
<template #prefix>
<Icon icon="mdi:account" />
</template>
</el-input>
</el-form-item>
<el-form-item>
<el-input v-model="form.password" placeholder="请输入密码">
<template #prefix>
<Icon icon="wpf:password1" />
</template>
</el-input>
</el-form-item>
<el-form-item v-if="PageType === 'register'">
<el-input v-model="form.passwordConfirm" placeholder="请再次输入密码">
<template #prefix>
<Icon icon="mdi:password-check-outline" />
</template>
</el-input>
</el-form-item>
<div v-if="PageType === 'login'" class="flex justify-between items-center">
<div>
<el-checkbox v-model="form.remember" label="自动登录" size="large" />
</div>
<div>
<el-link type="primary" :underline="false">忘记密码</el-link>
<el-text type="primary"> / </el-text>
<el-link type="primary" :underline="false" @click="goToRegister">注册</el-link>
</div>
</div>
<el-form-item>
<el-button v-if="PageType === 'login'" type="primary" class="w-full" @click="submit_login"
>登录</el-button
>
<el-button v-if="PageType === 'register'" type="primary" class="w-full">注册</el-button>
</el-form-item>
<div v-if="PageType === 'register'" class="text-right">
<el-link type="primary" :underline="false" @click="goToLogin">已有账号</el-link>
</div>
</el-form>
<div v-if="PageType === 'login'">
<el-divider>
<span class="text-10px">其他登录方式</span>
</el-divider>
<div class="flex justify-around">
<Icon
v-for="(item, index) in loginWay_list"
:key="index"
:icon="item.icon"
:style="{
color: item.color
}"
class="inline-block text-24px cursor-pointer"
/>
</div>
</div>
</div>
</template>