首先来看看qq的登录界面:
准备开发
制作一个窗口先
主进程代码:
import {BrowserWindow, webContents, app, ipcMain} from ‘electron‘
LoginWindow(); //暂时调用
ipcMain.on(‘quitApp‘, () => {
app.quit();
});
function LoginWindow() {
const loginURL = process.env.NODE_ENV === ‘development‘ ? `http://localhost:9080/#/login` : `file://${__dirname}/index.html/#/login`;
const loginWindow = new BrowserWindow({
width: 430,
height: 328,
alwaysOnTop: true,
modal: true,
frame: false,
darkTheme: true,
resizable: false,
minimizable: false,
maximizable: false,
transparent: true,
webPreferences: {
devTools: false,
}
});
loginWindow.setMenu(null);
loginWindow.loadURL(loginURL);
}
界面基本布局
我们先大概做一个这样的界面
页面代码:
<template>
<div class="mainWindow">
<header class="header"></header>
<main>
<div class="bg"></div>
<div class="body"></div>
</main>
<footer class="footer"></footer>
</div>
</template>
<script>
import ‘@/assets/css/login.css‘
export default {
}
</script>
样式代码:
/**
取消全部的外边距和内边距
*/
* {
padding: 0;
margin: 0;
}
/*设置窗口的样式*/
.mainWindow {
cursor: pointer; /*设置手型*/
border: 1px solid red; /*加一个边框 调试样式 最后要删除或者更改**/
width: 428px; /*设置宽度 必须要和主进程中设置的一样 不能大于主进程中设置的宽度 否则会出现滚动条*/
height: 326px; /*设置高度 必须要和主进程中设置的一样 不能大于主进程中设置的高度 否则会出现滚动条*/
position: relative; /*设置为相对定位*/
border-radius: 4px; /*设置圆角*/
}
/**
header的样式 header中只会有一个关闭按钮 处于右上角
*/
.mainWindow header.header {
position: absolute; /*设置绝对定位 因为背景在他下面*/
height: 30px; /*设置高度*/
background: rgba(0, 0, 0, 0.5); /*暂时设置的 后面要删除或者更改*/
border-radius: 4px 4px 0 0; /*给header的左上角 右上角设置圆角 不然会出现很尴尬的页面*/
width: 428px; /* 因为设置了绝对定位 设置宽度*/
}
/**
背景
*/
.mainWindow main .bg {
height: 124px; /*设置高度*/
width: 428px; /*设置宽度 也可以不用设置 因为这个元素没有设置绝对定位 所以默认就是100%*/
border-radius: 4px 4px 0 0; /*给左上角 右上角设置圆角 不然会出现很尴尬的页面 这里和header重合在一起了*/
background: blue; /*暂时设置的 后面要删除或者更改*/
}
/**
放置表单的元素
*/
.mainWindow main .body {
width: 428px; /*设置宽度 也可以不用设置 因为这个元素没有设置绝对定位 所以默认就是100%*/
height: 172px; /*设置高度 这里的高度是 主窗口(326) - footer(30) - 背景(124) 因为header设置了绝对定位 所以不用关 */
background: green; /*暂时设置的 后面要删除或者更改*/
}
.mainWindow footer.footer {
position: absolute; /* 设置绝对定位 要让他处于窗口的最底部*/
height: 30px; /*设置高度 */
background: red; /*暂时设置的 后面要删除或者更改*/
bottom: 0; /*让footer处于底部*/
width: 428px; /* 因为设置了绝对定位 设置宽度*/
}
窗口拖动
注意 不要使用内置的拖动 我们要自己实现!
在页面中加入以下代码就可以实现拖动了!
data() {
return {
windowX: 0,
windowY: 0,
}
},
mounted() {
let win = this.$electron.remote.getCurrentWindow();
document.addEventListener(‘mousedown‘, function (e) {
this.windowX = e.x;
this.windowY = e.y;
document.addEventListener(‘mousemove‘, moveEvent);
});
document.addEventListener(‘mouseup‘, function () {
this.windowX = 0;
this.windowY = 0;
document.removeEventListener(‘mousemove‘, moveEvent)
});
function moveEvent(e) {
win.setPosition(e.screenX - this.windowX, e.screenY - this.windowY)
}
}
设置背景图
将css里面的 .bg修改成:
.mainWindow main .bg {
height: 124px; /*设置高度*/
width: 428px; /*设置宽度 也可以不用设置 因为这个元素没有设置绝对定位 所以默认就是100%*/
border-radius: 4px 4px 0 0; /*给左上角 右上角设置圆角 不然会出现很尴尬的页面 这里和header重合在一起了*/
background: url("../images/login-back.gif") 10px;
background-size: 100%;
}
完成之后效果如如下:
制作顶部
顶部的logo和最小化就不做了 只做一个关闭的按钮
去阿里巴巴图标库下载字体文件之后放到assets/fonts目录中
在页面中加入:
import ‘@/assets/fonts/iconfont.css‘
header代码:
<header class="header">
<span class="iconfont icon-guanbi1"></span>
</header>
css文件
注意 在css .mainWindow header.header 添加
由于我背景图的关系 按钮可能不太明显 这问题不大 大家可以自己换一个图!
background: rgba(255, 255, 255, 0.2); /*暂时设置的 后面要删除或者更改*/
text-align: right;
.mainWindow header.header span{
display: inline-block;
height: 30px;
width:30px;
text-align: center;
line-height: 30px;
color:#E4393c;
}
.mainWindow header.header span:hover{
background-color: rgba(255,255,255,0.6);
}
制作表单页
表单界面代码
创建一个子组件 login.vue
写入如下代码:
<template>
<div class="form">
<form>
<div class="form_item"><i class="iconfont icon-1zhanghu"></i><input type="text"></div>
<div class="form_item"><i class="iconfont icon-mima1"></i><input type="password"></div>
</form>
<div class="buttons">
<button>登录</button>
</div>
</div>
</template>
<script>
export default {
name: "login"
}
</script>
表单页css
需要将 .mainWindow main .body 的背景颜色调成#FFFFFF
.form form{
padding:10px 90px 0 90px;
}
.form_item{
height: 40px;
position: relative;
}
.form_item i.iconfont{
position: absolute;
top:5px;
}
.form_item input{
outline: none;
border:none;
padding-left: 20px;
font-size: 16px;
width: 230px;
height: 30px;
border-bottom: 1px solid #CCC;
}
.buttons{
text-align: center;
}
.buttons button{
background-color: #CF000E;
border: none;
width: 250px;
color: #FFFFFF;
height: 35px;
cursor: pointer;
font-size: 14px;
border-radius: 4px;
outline: none;
}
效果
最后看到是这样的
复选框美化
组件代码
<div class="login_options">
<label><div class="option_item"><input type="checkbox"><span class="checked"><img src="@/assets/images/checked.png" ></span></div><i class="text">自动登录</i></label>
<label><div class="option_item"><input type="checkbox"><span class="checked"><img src="@/assets/images/checked.png" ></span></div><i class="text">记住密码</i></label>
<i class="text">忘记密码</i>
</div>
css代码
.login_options{
margin-bottom: 10px;
margin-top: 5px;
}
.login_options .option_item {
display: inline-block;
width: 13px;
height: 13px;
margin-right: 5px;
position: relative;
border: 1px solid orange;
vertical-align: middle;
cursor: pointer;
top: -2px;
}
.login_options .option_item input {
opacity: 0;
}
.login_options i.text{
display: inline-block;
margin-right: 14px;
font-size: 13px;
font-style: normal;
}
.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;
}
效果
注册页面
我们改进一点 因为qq的注册是一个连接到web页面去申请qq号码的 不过我做的是点击注册将界面切换到注册界面,只不过是
在写注册界面代码之前先将父组件种的login注释掉备用 (别删除哦) 在父组件中引入Register组件
注册的逻辑是这样的 在注册界面输入手机号和图形验证码 获取到短信验证码输入之后跳转到下一步输入密码
如果将全部的逻辑写到一个组件中会导致太长 虽然有办法解决 但是之后使用动画就很难看了!
界面代码
<template>
<div class="form">
<form>
<div class="form_item"><i class="iconfont icon-phone_icon"></i><input type="text"></div>
<div class="form_item">
<i class="iconfont icon-yanzhengma2"></i>
<input type="password">
<div class="captcha">
<img src="@/assets/images/captcha.png" >
</div>
</div>
<div class="form_item">
<i class="iconfont icon-yanzhengma5"></i>
<input type="password">
<div class="send_sms_captcha"><button>获取短信验证码</button></div>
</div>
</form>
<div class="buttons">
<button>下一步</button>
</div>
</div>
</template>
<script>
export default {
name: "register"
}
</script>
界面Css代码
.captcha {
position: absolute;
width: 120px;
height: 30px;
top: -2px;
right: 0;
}
.captcha img {
width: 100%;
height: 100%;
}
.send_sms_captcha {
position: absolute;
top: -2px;
right: 0;
}
.send_sms_captcha button{
width:120px;
height: 30px;
border:none;
outline: none;
cursor: pointer;
border-radius: 4px;
}
父组件代码
部分代码:
<main>
<div class="bg"></div>
<div class="body">
<!--<Login></Login>-->
<Register></Register>
</div>
</main>
效果
注册步骤2
界面代码
<template>
<div class="form">
<form>
<div class="form_item"><i class="iconfont icon-zaicishurumima"></i><input type="text"></div>
<div class="form_item"><i class="iconfont icon-mima1"></i><input type="password"></div>
<div class="login_options" style="text-align: center">
<label><div class="option_item"><input type="checkbox"><span class="checked"><img src="@/assets/images/checked.png" ></span></div><i class="text">自动登录</i></label>
<label><div class="option_item"><input type="checkbox"><span class="checked"><img src="@/assets/images/checked.png" ></span></div><i class="text">记住密码</i></label>
</div>
</form>
<div class="buttons">
<button>登录</button>
</div>
</div>
</template>
<script>
export default {
name: "steps2"
}
</script>
展示
footer代码
jie简介
在上面中footer里面显示了注册账号
其实这只是暂时的方案 为了方便截图
首先来分析一下 在登录页面的时候在底部显示注册账号 在注册第一步的时候在底部左侧显示已经账号,在第二步骤的时候显示返回上一步
我们有很多办法在子组件通知父组件去显示不同的文字
作者给出两个方案:
1: 通过子组件给父组件传值
2: 使用vuex
3: 将footer拆分到各个组件中
我们代码中使用拆分就行了 比较简单点
将父组件的footer删除
往组件login.vue steps1.vue steps2.vue 组件中加入footer
login.vue:
<template>
<div class="form">
<form>
<div class="form_item"><i class="iconfont icon-1zhanghu"></i><input type="text"></div>
<div class="form_item"><i class="iconfont icon-mima1"></i><input type="password"></div>
<div class="login_options">
<label><div class="option_item"><input type="checkbox"><span class="checked"><img src="@/assets/images/checked.png" ></span></div><i class="text">自动登录</i></label>
<label><div class="option_item"><input type="checkbox"><span class="checked"><img src="@/assets/images/checked.png" ></span></div><i class="text">记住密码</i></label>
<i class="text">忘记密码</i>
</div>
</form>
<div class="buttons">
<button>登录</button>
</div>
<footer class="footer">
<span @click="toggleWindow">注册账号</span>
</footer>
</div>
</template>
<script>
export default {
name: "login",
methods:{
toggleWindow(){
this.$store.dispatch(‘toggleLogin‘);
}
}
}
</script>
steps1.vue
<template>
<div class="form">
<form>
<div class="form_item"><i class="iconfont icon-phone_icon"></i><input type="text"></div>
<div class="form_item">
<i class="iconfont icon-yanzhengma2"></i>
<input type="password">
<div class="captcha">
<img src="@/assets/images/captcha.png" >
</div>
</div>
<div class="form_item">
<i class="iconfont icon-yanzhengma5"></i>
<input type="password">
<div class="send_sms_captcha"><button>获取短信验证码</button></div>
</div>
</form>
<div class="buttons">
<button @click="toggleSteps">下一步</button>
</div>
<footer class="footer">
<span @click="toggleWindow">已有账号</span>
</footer>
</div>
</template>
<script>
export default {
name: "steps1",
methods:{
toggleWindow(){
this.$store.dispatch(‘toggleLogin‘);
},
toggleSteps(){
this.$store.dispatch(‘toggleSteps‘);
},
}
}
</script>
steps2.vue
<template>
<div class="form">
<form>
<div class="form_item"><i class="iconfont icon-zaicishurumima"></i><input type="text"></div>
<div class="form_item"><i class="iconfont icon-mima1"></i><input type="password"></div>
<div class="login_options" style="text-align: center">
<label><div class="option_item"><input type="checkbox"><span class="checked"><img src="@/assets/images/checked.png" ></span></div><i class="text">立即登录</i></label>
<label><div class="option_item"><input type="checkbox"><span class="checked"><img src="@/assets/images/checked.png" ></span></div><i class="text">记住密码</i></label>
</div>
</form>
<div class="buttons">
<button>注册</button>
</div>
<footer class="footer">
<span @click="toggleSteps">返回上一步</span>
</footer>
</div>
</template>
<script>
export default {
name: "steps2",
methods:{
toggleSteps(){
this.$store.dispatch(‘toggleSteps‘);
},
}
}
</script>
vuex 代码
const state = {
steps: true,
login: true,
};
const actions = {
toggleSteps: function ({state, commit}) {
// state.steps = true;
state.steps = !state.steps;
},
toggleLogin({state, commit}){
state.login = !state.login;
}
};
export default ({
state,
actions
});
效果展示
添加动画效果
上面这些完成之后有点单调 尤其是切换的时候 我们可以用到 animateCss
animateCss 下载地址:https://daneden.github.io/ani...
子组件加入:
import ‘@/assets/css/animate.css‘
之后我们在代码中加入效果就行了
将父组件改成:
<main>
<div class="bg"></div>
<transition
:duration="500"
:enter-active-class="‘animated ‘ + (login ? ‘bounceInRight‘ : ‘bounceInLeft‘)"
:leave-active-class="‘animated ‘ + (login ? ‘bounceOutLeft‘ : ‘bounceOutRight‘)"
>
<Login v-if="login === true" key="login"></Login>
<Register v-else key="register"></Register>
</transition>
</main>
子组件 register.vue改成:
<transition
:duration="500"
:enter-active-class="‘animated ‘ + (steps ? ‘bounceInRight‘ : ‘bounceInLeft‘)"
:leave-active-class="‘animated ‘ + (steps ? ‘bounceOutLeft‘ : ‘bounceOutRight‘)"
>
<Steps1 v-if="steps === true" key="steps"></Steps1>
<Steps2 v-else key="steps"></Steps2>
</transition>
修改下css 因为要使用动画就要将main定位才能用
加入:
.mainWindow main {
position: absolute;
}
效果展示:
到这里就差不多了 代码太多没法一一发布上来 如果有需要的可以去github下载或者加QQ群 814270669
github地址:https://github.com/lihaotian0...
码云地址: https://gitee.com/leehaotian/...
我的github账号出了问题 一直登录不上去 所以就先发布到码云了