1、使用vuecli创建vue项目
2、安装electron
3、vue项目安装Electron-builder打包工具
4、在vue项目的src下有个background.js文件
5、安装remote模块
6、代码
7、效果图
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
到此这篇关于electron vue 模仿qq登录界面的文章就介绍到这了,更多相关electron vue qq登录界面内容请搜索软件开发网以前的文章或继续浏览下面的相关文章希望大家以后多多支持软件开发网!