1. 构建登录组件
router.js:设置路由
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'index',
component: () => import('./views/index.vue')
},
{
path: '/login',
name: 'login',
component: () => import('./views/Login.vue')
}
]
});
//路由守卫
router.beforeEach((to, from, next) => {
const isLogin = localStorage.ele_login ? true : false;
if (to.path == "/login") {
next();
} else {
//是否在登录状态
isLogin ? next() : next('/login')
}
})
export default router;
2. 展示登录页面
组件的封装:
InputGroup.vue:
< template >
<div id="text_group">
<!-- 组件结构 -->
<!-- 组件容器 -->
<div class="input_group">
<!-- 输入框 -->
<!-- @input="$emit(...)":获取input里面的值 -->
<!-- @input是用来定义输入的,是接收其他组件传过来的数据的 -->
<!-- 父组件可以使用props把数据传给子组件 -->
<!-- 子组件可以使用$emit触发父组件的自定义事件 -->
<input : type="type" :value="value" :placeholder="placeholder" :name="name" @input="$emit('input',$event.target.value)">
<!-- 输入框后面的按钮 -->
<button v-if="btnTitle" : disabled="disabled" @click="$emit('btnClick')">{{ btnTitle }}</button>
<!-- 错误提醒 -->
<div v-if="error" class="invalid-feedback">{{ error }}</div>
</div>
</div >
</template >
<script>
export default {
name: "inputGroup",
//props:需要使用该组件时传递的参数
props:{
//type:输入内容的类型
type: {
type: String,
default:"text"
},
//value:输入框里的值
value:String,
placeholder:String,
name:String,
btnTitle:String,
disabled:Boolean,
error:String
}
}
</script>
<style scoped>
.input_group {
border: 1px solid #ccc;
border-radius: 4px;
padding: 10px;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.input_group input {
height: 100%;
width: 60%;
outline: none;
}
.input_group button {
border: none;
outline: none;
background: #fff;
}
.input_group button[disabled] {
color: #aaa;
}
.is-invalid {
border: 1px solid red;
}
.invalid-feedback {
color: red;
padding-top: 5px;
}
</style>
Login.vue:
Login.vue:
<template>
<div class="login">
<div class="logo">
<img src="../assets/logo.jpg" alt="my login image">
</div>
<!-- 手机号 -->
<InputGroup
type="number"
v-model="phone"
placeholder="手机号"
:btnTitle="btnTitle"
:disabled="disabled"
:error="errors.phone"
@btnClick="getVerifyCode"
/>
<!-- 验证码 -->
<InputGroup type="number" v-model="verifyCode" placeholder="验证码" :error="errors.code"/>
<!-- 用户服务协议 -->
<div class="login_des">
<p>
新用户登录即自动注册,表示已同意
<span>《用户服务协议》</span>
</p>
</div>
<!-- 登录按钮 -->
<div class="login_btn">
<button :disabled="isClick" @click="handleLogin">登录</button>
</div>
</div>
</template>
<script>
import InputGroup from "../components/InputGroup";
export default {
name: "login",
data() {
return {
phone: "",
verifyCode: "",
errors: {},
btnTitle: "获取验证码",
disabled: false
};
},
components: {
InputGroup
}
};
</script>
<style scoped>
.login {
width: 100%;
height: 100%;
padding: 30px;
box-sizing: border-box;
background: #fff;
}
.logo {
text-align: center;
}
.logo img {
width: 150px;
}
.text_group,
.login_des,
.login_btn {
margin-top: 20px;
}
.login_des {
color: #aaa;
line-height: 22px;
}
.login_des span {
color: #4d90fe;
}
.login_btn button {
width: 100%;
height: 40px;
background-color: #48ca38;
border-radius: 4px;
color: white;
font-size: 14px;
border: none;
outline: none;
}
.login_btn button[disabled] {
background-color: #8bda81;
}
</style>
3. 验证码倒计时
Login.vue:
methods: {
getVerifyCode() {
//先判断手机号码是否合法
if (this.validatePhone()) {
this.validateBtn();
},
//验证码倒计时
validateBtn() {
let time = 60;
let timer = setInterval(() => {
//当time=0时,清除clearInterval
if (time == 0) {
clearInterval(timer);
this.btnTitle = "获取验证码";
//当还没有获取验证码时,是能点击的
this.disabled = false;
} else {
// 倒计时
this.btnTitle = time + "秒后重试";
//当正在获取验证码时,不能点击
this.disabled = true;
time--;
}
}, 1000);
},
// 验证手机号码
validatePhone() {
//手机号码为空时
if (!this.phone) {
this.errors = {
phone: "手机号码不能为空"
};
return false;
} else if (!/^1[345678]\d{9}$/.test(this.phone)) {
this.errors = {
phone: "请填写正确的手机号码"
};
return false;
} else { //如果手机号码没有问题
this.errors = {};
return true;
}
}
},
4. 获取短信验证码
聚合数据短信API
安装axios,然后可以发送请求了。
main.js:
import axios from 'axios'
Vue.prototype.$axios=axios
调用已经写好的接口,在根路径下创建vue.config.js:
module.exports = {
devServer: {
open: true,
host: 'localhost',
port: 8081,
https: false,
hotOnly: false,
proxy: {
// 配置跨域
'/api': {
target: 'https://ele-interface.herokuapp.com/api/',
ws: true,
changOrigin: true,
pathRewrite: {
'^/api': ''
}
}
},
before: app => { }
}
};
重启一次,用axios请求数据:需要用到短信API的key(短信模板配置申请通过后会生成)以及API的AppKey
getVerifyCode() {
//先判断手机号码是否合法
if (this.validatePhone()) {
this.validateBtn();
// 发送网络请求
//"/api"就是vue.config.js中的url
this.$axios.post("/api/posts/sms_send", {
//传递我们所需要的内容
tpl_id: "申请成功后的key",
key: "短信API的AppKey",
phone: this.phone
})
.then(res => {
console.log(res);
})
}
},
5. 检验手机号码和验证
methods: {
handleLogin() {
// 取消错误提醒
this.errors = {};
// 发送请求
this.$axios
.post("/api/posts/sms_back", {
phone: this.phone,
code: this.verifyCode
})
.then(res => {
// console.log(res);
// 检验成功 设置登录状态并且跳转到/
localStorage.setItem("ele_login", true);
this.$router.push("/");
})
.catch(err => {
// 返回错误信息
this.errors = {
code: err.response.data.msg
};
});
},
}
这样则表示发送验证码成功