乐趣区

electron 仿制QQ登录界面

首先来看看 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” alt=””></span></div><i class=”text”> 自动登录 </i></label>
<label><div class=”option_item”><input type=”checkbox”><span class=”checked”><img src=”@/assets/images/checked.png” alt=””></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” alt=””>
</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” alt=””></span></div><i class=”text”> 自动登录 </i></label>
<label><div class=”option_item”><input type=”checkbox”><span class=”checked”><img src=”@/assets/images/checked.png” alt=””></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: 使用 vuex3: 将 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” alt=””></span></div><i class=”text”> 自动登录 </i></label>
<label><div class=”option_item”><input type=”checkbox”><span class=”checked”><img src=”@/assets/images/checked.png” alt=””></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” alt=””>
</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” alt=””></span></div><i class=”text”> 立即登录 </i></label>
<label><div class=”option_item”><input type=”checkbox”><span class=”checked”><img src=”@/assets/images/checked.png” alt=””></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 群 814270669github 地址:https://github.com/lihaotian0… 码云地址: https://gitee.com/leehaotian/…
我的 github 账号出了问题 一直登录不上去 所以就先发布到码云了

退出移动版