electron vue 模仿qq登录界面功能实现
1、使用vuecli创建vue项目
我用的vue2
vue create qq_test
2、安装electron
npm install electron -g //or npm install electron@12.0.11 //老版本
3、vue项目安装Electron-builder打包工具
版本我选择的是12
vue add electron-builder
4、在vue项目的src下有个background.js文件
background.js里面有默认的配置,修改后我的配置大概如下
'use strict' import { app, protocol, BrowserWindow, Menu, Tray } 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' // 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: 432, height: 331, alwaysOnTop: true,//窗口一直保持在其他窗口前面 modal: true, frame: false, darkTheme: true, resizable: false,//用户不可以调整窗口 center: true, // 窗口居中 transparent: false,//窗口透明 show: false,// 显示窗口将没有视觉闪烁(配合下面的ready-to-show事件) hasShadow: true,//窗口是否有阴影 webPreferences: { // Use pluginOptions.nodeIntegration, leave this alone // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info // nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION, // contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION, devTools: true,//客户端可以打开开发者工具(在客户端打开快捷键:ctrl+shift+i) nodeIntegration: true, enableRemoteModule: true, // 使用remote模块(electron12版本就开始废除了,需要我们自己安装remote模块) contextIsolation: false, //解决axios请求跨域问题(不推荐,不安全,但简单好用) webSecurity: false, }, }) if (process.env.WEBPACK_DEV_SERVER_URL) { // Load the url of the dev server if in development mode await 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 development win.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 + Q if (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.once('ready-to-show', () => { win.show(); }) 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() }) // 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() }) } }
5、安装remote模块
因为electron12版本开始就废除了remote模块,我们需要自己安装
npm install @electron/remote --save //or cnpm install @electron/remote --save
能在客户端实现 最大化、最小化、关闭功能
6、代码
1、Login.vue页面(登录页面)
里面的最小化图标、关闭图标、最大化图标 请自己去iconfont-阿里巴巴矢量图标库下载
<template> <div class="login" style="overflow:hidden;"> <!-- 顶部 --> <header class="header"> <!-- 最小化按钮 --> <span @click="minwin" class="iconfont icon-24gl-minimization"></span> <!-- 关闭按钮 --> <span @click="close" class="iconfont icon-guanbi"></span> </header> <main> <!-- 顶部背景图 --> <div class="bg"> <img style="" src="../../assets/images/login.gif" /> </div> <!-- 登录表单组件 --> <div class="body"> <Login_form></Login_form> </div> </main> <footer class="footer"> <div class="zczh" @click="zc">注册账号</div> <div> <span title="二维码登录" class="iconfont icon-erweima"></span> </div> </footer> </div> </template> <script> import "@/assets/css/login.css"; import "@/assets/fonts/gb/iconfont.css"; import "@/assets/fonts/zxh/iconfont.css"; import "@/assets/fonts/ewm/iconfont.css"; import Login_form from "@/components/Login_form.vue"; //网页测试要关闭,打包成软件要启动 const { remote } = window.require("electron"); export default { name: "login", data() { return {}; }, components: { Login_form, }, methods: { close() { // 只是关闭窗口,软件不退出 // remote.getCurrentWindow().hide() // 关闭窗口,退出软件 remote.getCurrentWindow().close(); }, // 最小化 minwin() { // 最小化,在任务栏显示 remote.getCurrentWindow().minimize() // 隐藏窗口,任务栏也隐藏 // remote.getCurrentWindow().hide(); }, zc() { this.$router.push("/reg"); }, }, mounted() { //显示窗口 remote.getCurrentWindow().show(); }, }; </script> <style lang="scss" scpoed> .login { max-width: 900px; overflow: hidden; min-width: 430px; .bg { img { width: 430px; height: 124px; object-fit: cover; } } } </style>
2、login.css
/** 取消全部的外边距和内边距 */ * { padding: 0; margin: 0; } /*设置窗口的样式*/ .login { cursor: default; /*设置手型*/ /* border: 1px solid red; */ /*加一个边框 调试样式 最后要删除或者更改**/ width: 430px; /*设置宽度 必须要和主进程中设置的一样 不能大于主进程中设置的宽度 否则会出现滚动条*/ height: 329px; /*设置高度 必须要和主进程中设置的一样 不能大于主进程中设置的高度 否则会出现滚动条*/ position: relative; /*设置为相对定位*/ /* border-radius: 4px; */ /*设置圆角*/ border: 1px solid #464545; /* 拖 */ -webkit-app-region: drag; /* 禁止滚动条 */ overflow: hidden; } /** header的样式 header中只会有一个关闭按钮 处于右上角 */ .login header.header { position: absolute; /*设置绝对定位 因为背景在他下面*/ height: 30px; /*设置高度*/ /* border-radius: 20px 20px 0 0; */ /*给header的左上角 右上角设置圆角 不然会出现很尴尬的页面*/ width: 428px; /* 因为设置了绝对定位 设置宽度*/ /* background: rgba(255, 255, 255, 0.2); */ /*暂时设置的 后面要删除或者更改*/ text-align: right; } /** 背景 */ .login main .bg { height: 124px; /*设置高度*/ width: 430px; /*设置宽度 也可以不用设置 因为这个元素没有设置绝对定位 所以默认就是100%*/ /* border-radius: 4px 4px 0 0; */ /*给左上角 右上角设置圆角 不然会出现很尴尬的页面 这里和header重合在一起了*/ /* background: url("@/assets/images/login.gif") 10px; */ background-size: 100%; } /** 放置表单的元素 */ .login main .body { width: 428px; /*设置宽度 也可以不用设置 因为这个元素没有设置绝对定位 所以默认就是100%*/ height: 200px; /*设置高度 这里的高度是 主窗口(326) - footer(30) - 背景(124) 因为header设置了绝对定位 所以不用关 */ /* background: green; */ /*暂时设置的 后面要删除或者更改*/ } .login footer.footer { position: absolute; /* 设置绝对定位 要让他处于窗口的最底部*/ height: 30px; /*设置高度 */ /* background: red; */ /*暂时设置的 后面要删除或者更改*/ bottom: 0; /*让footer处于底部*/ width: 397.99px; /* 因为设置了绝对定位 设置宽度*/ /* border-radius: 0 0 5px 5px; */ background-color: #FFFFFF; } .login header.header span{ display: inline-block; height: 30px; width:30px; text-align: center; line-height: 30px; color:#E4393c; cursor: pointer; } .login header.header span:hover{ background-color: rgba(255,255,255,0.6); cursor: pointer; } .zczh{ cursor: pointer; color: #7c7a7a; user-select: none; -webkit-app-region: no-drag; } .zczh:hover{ cursor: pointer; color: black; user-select: none; -webkit-app-region: no-drag; }
3、Login_form.vue组件
里面的resetMessage信息提示是我重新封装的element组件(我就不放上去了)
里面的最小化图标、关闭图标、最大化图标 请自己去iconfont-阿里巴巴矢量图标库下载
<template> <div class="login_form"> <form> <div class="form_item"> <i class="iconfont icon-zhanghao"></i ><input @focus="i1_get" @blur="i1_lose" @input="input1($event)" id="text" v-model="email" type="email" :placeholder="placeholder1" @keyup.enter="login" /> </div> <div class="form_item"> <i class="iconfont icon-mima"></i ><input @focus="i2_get" @blur="i2_lose" id="text2" v-model="password" type="password" :placeholder="placeholder2" @keyup.enter="login" /> </div> <div class="login_options"> <label ><div class="option_item"> <input :disabled="jzmm" v-model="zddl" type="checkbox" autocomplete="off" /> </div> <i class="text">记住账号</i></label > <label ><div class="option_item"> <input @click="jzmm_mm" v-model="jzmm" type="checkbox" autocomplete="off" /> </div> <i class="text">记住密码</i></label > <i class="text wjmm">忘记密码</i> </div> </form> <div class="buttons"> <button @click="login">登录</button> </div> </div> </template> <script> import "@/assets/css/login_form.css"; import "@/assets/fonts/xlk/iconfont.css"; import "@/assets/fonts/slk/iconfont.css"; import "@/assets/fonts/zh/iconfont.css"; import "@/assets/fonts/mm/iconfont.css"; //网页测试要关闭,打包成软件要启动 const { remote } = window.require("electron"); export default { name: "Login_form", data() { return { email: "", password: "", placeholder1: "邮箱", placeholder2: "密码", zddl: false, jzmm: false, }; }, methods: { i1_get() { if (!this.email) { this.placeholder1 = ""; } }, i2_get() { if (!this.password) { this.placeholder2 = ""; } }, i1_lose() { if (!this.email) { this.placeholder1 = "邮箱"; } }, i2_lose() { if (!this.password) { this.placeholder2 = "密码"; } }, input1(e) { if (e.target.value == "") { // console.log(val); this.password = ""; this.placeholder2 = "密码"; } }, login() { var eamil_gz = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/; switch (true) { case this.email == "": this.waring("邮箱不能为空!"); break; case !eamil_gz.test(this.email): this.error("邮箱格式错误"); break; case this.password == "": this.waring("密码不能为空!"); break; default: let data = { log_email: this.email, log_password: this.password, }; this.$axios .post("/login/login", data) // 在后台查询信息 返回res结果 .then((res) => { // console.log(res.data); switch (true) { case res.data.code == 200: //登录成功 this.success(res.data.msg); //本地存储 localStorage.setItem("email", this.email); localStorage.setItem("token", res.data.token); if (this.zddl == true) { localStorage.setItem("zddl", true); } else { localStorage.removeItem("zddl"); localStorage.removeItem("email"); } if (this.jzmm == true) { localStorage.setItem("zddl", true); localStorage.setItem("jzmm", true); localStorage.setItem("mm", this.password); } else { localStorage.removeItem("jzmm"); localStorage.removeItem("mm"); } this.$router.push("/chat_index"); //登录成功跳转会有点闪屏,先隐藏,到另外一个路由再显示 remote.getCurrentWindow().hide(); //登录之后设置窗口在电脑桌面显示位置 remote.getCurrentWindow().setPosition(386, 192); break; case res.data.code == 404: //邮箱不存在 this.error(res.data.msg); break; case res.data.code == 300: //密码错误 this.error(res.data.msg); break; case res.data.code == 400: //用户异常 this.error(res.data.msg); break; default: //未知错误 this.error(res.data.msg); break; } }) .catch((error) => { //报错 }); break; } }, //记住密码 jzmm_mm() { if (this.zddl == false) { this.zddl = true; } this.jzmm = true; }, // 警告提示 waring(title) { this.$resetMessage({ message: `${title}`, type: "warning", }); }, // 成功提示 success(title) { this.$resetMessage({ message: `${title}`, type: "success", }); }, // 错误提示 error(title) { this.$resetMessage.error(`${title}`); }, }, mounted() { // 读取本地存储账号信息 if (localStorage.getItem("zddl")) { this.zddl = true; this.email = localStorage.getItem("email"); } if (localStorage.getItem("jzmm")) { this.jzmm = true; this.password = localStorage.getItem("mm"); } if (localStorage.getItem("email")) { this.email = localStorage.getItem("email"); } if (!this.email) { document.getElementById("text").focus(); } else { document.getElementById("text2").focus(); } }, }; </script>
4、login_form.css
.login_form{ -webkit-app-region: drag; background-color: #FFFFFF; } .login_form form { padding: 10px 90px 0 90px; } .form_item { height: 40px; position: relative; } .form_item div { float: right; margin-right: 5px; } .form_item i.iconfont { position: absolute; top: 5px; } .form_item input { outline: none; border: none; padding-left: 30px; font-size: 16px; width: 230px; height: 30px; border-bottom: 1px solid #CCC; user-select: none; -webkit-app-region: no-drag; } .buttons { text-align: center; } .buttons button { background-color: #0786b4; border: none; width: 250px; color: #FFFFFF; height: 35px; cursor: pointer; font-size: 14px; border-radius: 4px; outline: none; -webkit-app-region: no-drag; user-select: none; } .buttons button:hover { background-color: #0aaae4; border: none; width: 250px; color: #FFFFFF; height: 35px; cursor: pointer; font-size: 14px; border-radius: 4px; outline: none; -webkit-app-region: no-drag; user-select: none; } .checkbox { display: flex; justify-content: center; align-items: center; } .footer { display: flex; justify-content: space-between; padding: 5px 15px 5px 15px; align-items: center; } .login_options { margin-bottom: 10px; margin-top: 5px; } .login_options .option_item { display: inline-block; align-items: center; width: 13px; height: 13px; margin-right: 5px; position: relative; cursor: pointer; top: 2px; -webkit-app-region: no-drag; } .login_options .option_item input { /* font-size: 13px; */ -webkit-app-region: no-drag; } .login_options i.text { display: inline-block; margin-right: 14px; font-size: 13px; font-style: normal; user-select: none; -webkit-app-region: no-drag; } .login_options .option_item span.checked { position: absolute; top: -4px; right: -3px; font-weight: bold; display: inline-block; width: 20px; height: 20px; cursor: pointer; } .option_item span.checked img { width: 100%; height: 100%; } input[type="checkbox"]+span { opacity: 0; } input[type="checkbox"]:checked+span { opacity: 1; } .wjmm { cursor: pointer; color: rgb(139, 134, 134); } .wjmm:hover { cursor: pointer; color: rgb(19, 18, 18); }
5、package.json文件
{ "name": "qq_test", "version": "0.1.0", "private": true, "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", "electron:build": "vue-cli-service electron:build", "electron:serve": "vue-cli-service electron:serve", "postinstall": "electron-builder install-app-deps", "postuninstall": "electron-builder install-app-deps" }, "main": "background.js", "dependencies": { "axios": "^0.27.2", "core-js": "^3.8.3", "element-ui": "^2.15.9", "express": "^4.18.1", "qs": "^6.11.0", "socket.io": "^4.5.1", "socket.io-client": "^3.1.0", "vscode-material-icon-theme-js": "^1.0.7", "vue": "^2.6.14", "vue-router": "^3.5.1", "vue-socket.io": "^3.0.10", "vuex": "^3.6.2" }, "devDependencies": { "@vue/cli-plugin-babel": "~5.0.0", "@vue/cli-plugin-router": "~5.0.0", "@vue/cli-plugin-vuex": "~5.0.0", "@vue/cli-service": "~5.0.0", "electron": "^12.0.0", "electron-devtools-installer": "^3.1.0", "sass": "^1.32.7", "sass-loader": "^12.0.0", "vue-cli-plugin-electron-builder": "~2.1.1", "vue-template-compiler": "^2.6.14" }, "browserslist": [ "> 1%", "last 2 versions", "not dead" ] }
6、main.js
import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' import axios from "axios"; //引入axios Vue.prototype.$axios = axios; //axios跟很多第三方模块不同的一点是它不能直接使用use方法,而是用这种方法 //配合文章第4步解释 本地网站 axios.defaults.baseURL = 'http://www.electron.com/index.php/api';//开发环境 //引入element组件 import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI); //重写提示框只提示一次 import resetMessage from '@/assets/js/resetMessage' Vue.prototype.$resetMessage = resetMessage Vue.use( new VueSocketIO({ debug: false, // 宝塔 IP:端口号 (生产环境) connection: SocketIO('http://127.0.0.1:3000', {//开发环境 autoConnect: false // 取消自动连接 }), extraHeaders: { 'Access-Control-Allow-Origin': '*' } }) ) //客户端禁止按鼠标返回键返回上一个路由 window.addEventListener('popstate', function() { history.pushState(null, null, document.URL) }) Vue.config.productionTip = false new Vue({ router, store, render: h => h(App) }).$mount('#app')
7、效果图
本地测试
npm run electron:serve
关于electronvue模仿qq登录界面的文章就介绍至此,更多相关electronvueqq登录界面内容请搜索编程宝库以前的文章,希望以后支持编程宝库!
1.引入cdn资源<link rel="stylesheet" href="https://unpkg.com/element-ui@2.3.5/lib/theme-c ...