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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/941625.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯嵌入式备赛教程(1、led,2、lcd,3、key)

一、工程模版创建流程 第一步 创建新项目 第二步 选择型号和管脚封装 第三步 RCC使能 外部时钟&#xff0c;高速外部时钟 第四步晶振时钟配置 由数据手册7.1可知外部晶振频率为24MHz 最后一项设置为80 按下回车他会自动配置时钟 第五步&#xff0c;如果不勾选可能程序只会…

C++----------函数的调用机制

栈帧的创建与销毁 栈帧创建过程 当一个函数被调用时&#xff0c;系统会在程序的栈空间中为该函数创建一个栈帧。首先&#xff0c;会将函数的返回地址&#xff08;即调用该函数的下一条指令的地址&#xff09;压入栈中&#xff0c;这确保函数执行完后能回到正确的位置继续执行后…

C语言初阶习题【9】数9的个数

1.编写程序数一下 1到 100 的所有整数中出现多少个数字9 2.思路 循环遍历1到100&#xff0c;需要判断每一位的个位数是否为9&#xff0c;十位数是否为9&#xff0c;每次符合条件就count进行计数&#xff0c;最后输出count&#xff0c;即可 3.code #define _CRT_SECURE_NO_W…

模型 课题分离

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。明确自我与他人责任。 1 课题分离的应用 1.1课题分离在心理治疗中的应用案例&#xff1a;李晓的故事 李晓&#xff0c;一位28岁的软件工程师&#xff0c;在北京打拼。他面临着工作、家庭和感情的多重…

Docker 入门:如何使用 Docker 容器化 AI 项目(一)

引言 在人工智能&#xff08;AI&#xff09;项目的开发和部署过程中&#xff0c;环境配置和依赖管理往往是开发者遇到的挑战之一。开发者通常需要在不同的机器上运行同样的代码&#xff0c;确保每个人使用的环境一致&#xff0c;才能避免 “在我的机器上可以运行”的尴尬问题。…

Android修行手册 - 移动端几种常用动画方案对比

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

抢单人机交互「新红利」!哪些细分赛道“多金”?

受终端用户的智能座舱体验需求驱动&#xff0c;视觉、听觉、触觉等人机交互方式加速焕新。 一方面&#xff0c;人机多模交互引领&#xff0c;车载声学进入新周期。根据高工智能汽车研究院统计数据&#xff0c;单车的车载扬声器搭载量正在快速起量。 很显然&#xff0c;作为智…

Linux shell脚本用于常见图片png、jpg、jpeg、webp、tiff格式批量添加文本水印

Linux Debian12基于ImageMagick图像处理工具编写shell脚本用于常见图片png、jpg、jpeg、webp、tiff格式批量添加文本水印 BiliBili视频链接&#xff1a; Linux shell脚本对常见图片格式转换webp和添加文本水印 在Linux系统中&#xff0c;使用ImageMagick可以图片格式转换&…

本地电脑使用命令行上传文件至远程服务器

将本地文件上传到远程服务器&#xff0c;在本地电脑中cmd使用该命令&#xff1a; scp C:/Users/"你的用户名"/Desktop/environment.yml ws:~/environment.yml 其中&#xff0c;C:/Users/“你的用户名”/Desktop/environment.yml是本地文件的路径&#xff0c; ~/en…

004最长回文子串

#include #include #include using namespace std; class Solution { public: string longestPalindrome(string s) { int n s.size(); if (n < 2) { return s; } int maxLen 1;int begin 0;// dp[i][j] 表示 s[i..j] 是否是回文串vector<vector<int>> …

蓝桥杯刷题——day8

蓝桥杯刷题——day8 题目一题干解题思路代码 题目二题干解题思路代码 题目一 题干 N 架飞机准备降落到某个只有一条跑道的机场。其中第i架飞机在 Ti时刻到达机场上空&#xff0c;到达时它的剩余油料还可以继续盘旋 Di个单位时间&#xff0c;即它最早可以于 Ti时刻开始降落&am…

ue5 pcg(程序内容生成)真的简单方便,就5个节点

总结&#xff1a; 前情提示 鼠标单击右键平移节点 1.编辑-》插件-》procedural->勾选两个插件 2.右键-》pcg图表-》拖拽进入场景 3.先看点point 右键-》调试(快捷键d)->右侧设置粒子数 3.1调整粒子数 可以在右侧输入框&#xff0c;使用加减乘除 4.1 表面采样器 …

【编辑器扩展】打开持久化路径/缓存路径/DataPath/StreamingAssetsPath文件夹

代码 [MenuItem("Assets/Open Explorer/PersistentDataPath")]public static void OpenPersistentDataPath(){Application.OpenURL(Application.persistentDataPath);}[MenuItem("Assets/Open Explorer/DataPath")]public static void OpenDataPath(){Appl…

STM32——“SPI Flash”

引入 在给单片机写程序的时候&#xff0c;有时会用到显示屏&#xff0c;就拿市面上的0.96寸单色显示器来说&#xff0c;一张全屏的图片就占用8x1281024个字节&#xff0c;即1kb的空间&#xff0c;这对于单片机来说确实有点奢侈&#xff0c;于是我买了一个8Mb的SPI Flash&#x…

Linux 下SVN新手操作手册

下面来介绍Linux 下 SVN操作方法&#xff1a; 1、SVN的安装 Centos 7 安装Subversion sudo yum -y install subversion Ubuntu 安装Subversion sudo apt-get install subversion 自定义安装&#xff0c;官方地址&#xff1a;https://subversion.apache.org/ 2、SVN的使用…

中国信通院致信感谢易保全:肯定贡献能力,期许未来合作

近日&#xff0c;中国信息通信研究院&#xff08;以下简称“中国信通院”&#xff09;向易保全发感谢信表达谢意&#xff0c;对其在中国信通院牵头的“铸基计划”——企业数字化转型高质量发展推进行动实施中展现出的重要贡献给予了高度评价和肯定&#xff0c;并展望了双方至20…

【微信小程序】1|底部图标 | 我的咖啡店-综合实训

底部图标 引言 在微信小程序开发中&#xff0c;底部导航栏&#xff08;tabBar&#xff09;是用户界面的重要组成部分&#xff0c;它为用户提供了快速切换不同页面的功能。今天&#xff0c;我们将通过一个实际案例——“我的咖啡店”小程序&#xff0c;来详细解析如何配置底部图…

(补)算法刷题Day24: BM61 矩阵最长递增路径

题目链接 思路 方法一&#xff1a;dfs暴力回溯 使用原始used数组4个方向遍历框架 &#xff0c; 全局添加一个最大值判断最大的路径长度。 方法二&#xff1a;加上dp数组记忆的优雅回溯 抛弃掉used数组&#xff0c;使用dp数组来记忆遍历过的节点的最长递增路径长度。每遍历到已…

基于单片机的智能电子秤(论文+源码)

1.设计框架 本次智能电子秤单片机控制系统由7个部分构成&#xff0c;包括手机&#xff0c;蓝牙传输模块&#xff0c;LCD液晶显示模块&#xff0c;单片机控制系统、压力传感器检测电路&#xff0c;按键电路以及复位晶振&#xff0c;整体框图如图2.1所示。在功能上&#xff0c;整…

【保姆级别教程】VMware虚拟机安装Mac OS15苹果系统附带【VMware TooLS安装】【解锁虚拟机】和【Mac OS与真机共享文件夹】手把手教程

目录 准备工作 一、安装虚拟机 二、解锁系统 三、安装系统 四、部署系统 五、安装VMware Tools(选做) 为什么要安装VMware Tools&#xff0c;这是啥玩意&#xff1f; 六、配置共享文件夹(选做) 为什么要共享文件夹&#xff1f; 注意事项&#xff1a; 七、安装完成 准…