其三:登陆&注册部分开发
布局
页面其实很简单,照着画就行了。登陆和注册的页面基本一致,可以写好一个复制一份。
逻辑
先来理一下假登陆注册的逻辑吧。
- 无论用户输入什么,只要点击登陆按钮就算登陆成功,跳转到Home页。
- 无论用户输入什么,只要点击注册按钮,就算注册成功,跳转到登陆页。
- 点击“立即注册”,跳转到注册页。
- 点击“已有账号去登陆”,跳转到登陆页。
- 登陆后,无法再回到登陆页面(无论是通过按钮、回退还是改url),只能跳转到Home页。
接下来从第一条开始把逻辑写了。
登陆及登陆校验
在登陆按钮绑定点击事件。事件内部调用this.$router.push({name:“Home”})。
在跳转前,需要改变一个状态让浏览器知道已经登陆了,选择localStorage。
handleLogin() {
localStorage.isLogin = true
this.$router.push({ name: "Home" })
},
示范代码是vue3版本的,该版本下可以在setup函数中直接写router。
import {useRouter} from "vue-router"
setup(){
const router = useRouter()
localStorage.isLogin = true
router.push({name:"Home"})
}
2、3、4的逻辑差不多,点击按钮然后跳转,不需要其他状态改变。
现在来解决“没登录前,只能访问登陆页面;登陆后,只能访问Home页面”这个问题。
可以在路由中设置beforeEach,这是一种路由守卫。会在每个路由发生跳转之前执行。可以该函数里判断即将跳转的页面是什么页面,并判断跳转状态是否正确。
跳转状态正确/当前页面是登陆页/当前页面是注册页=》允许跳转
如果不满足条件,则跳转回登陆页。
router.beforeEach((to, from, next) => {
const { isLogin } = localStorage
isLogin || to.name === "Login" || to.name === "Signin"
? next()
: next({ name: "Login" })
})
还可以在路由内部设置beforeEnter,会在当前路由发生跳转前执行。判断是否已经登陆,是则跳转到Home页,不是则允许跳转。
beforeEnter(to, from, next) {
const { isLogin } = localStorage
isLogin ? next({ name: "Home" }) : next()
},
跳转后页面不在顶部
跳转后是这个样子的。其实是登陆的样式属性没有设置scoped。
但是刷新一次就可以恢复正常。
我的解决方法是,用路由守卫判断是否有上一个页面,有的话就刷新。没有(因为reload()和go(0)都是强制刷新,刷新后就没有上一个页面)的话就什么都不做。
beforeRouteEnter(to, from, next) {
next(() => {
if (from.name) {
location.reload()
}
})
},
或者给登陆里的style加上scoped。。。
使用模拟接口实现登陆
使用fastmock模拟一个假的接口
使用axios发送请求。
- 发送的地址:上图的接口根地址+/login
- 发送的数据:{username:"",password:""}
- 发送的结果:通过then、catch接受
handleLogin(){
this.$axios.get("发送的地址","发送的数据")
.then(()=>{//跳转到到登陆页})
.catch(()=>{//提示登陆失败})
}
可以封装一下axios函数。在src目录下新建一个utils文件夹。
封装的一些全局函数可以保存在这里。
import axios from "axios"
export const post = (url, data = {}) => {
return new Promise((resolve, reject) => {
axios
.post(url, data, {
baseURL:
"接口根地址",
headers: {
"Content-Type": "application/json" //一些设置,
},
})
.then(
(res) => {
resolve(res.data)
},
(err) => {
reject(err)
}
)
})
}
调用时
const result = post("/login", {
username: this.userMobie,
password: this.passWord,
})
result.then((info) => {
if (info.error === 0) {
localStorage.isLogin = true
this.$router.push({ name: "Home" })
} else {
console.log("登陆失败")
}
})
info的格式可以自己在fastmock上指定。我的格式是这样的
{
error:0,
error_message:"error!==0时的错误信息"
}
全局功能组件
编写一个弹窗效果的组件,可以提示用户登录成功/失败
考虑到可以复用,写成全局组件。
这个组件应该是一个在页面上弹窗的效果,所以可以用fixed定位。
组件展示的内容可以由调用它的父组件传入,组件展示的时间也可以由父组件决定。
- 一个采用定位,半透明的弹窗
- 使用v-if/v-show决定是否展示
- 使用props决定展示的内容
- 加入transition实现过渡效果
<div>{{message}}</div>
<Toast v-if="showMessage" :message="data.message"/>
const showToast = (message,showTime)=>{
data.message = message
setTimeout(()=>{
showMessage = false
},showTime)
}
<transition name="fade">
<Toast v-if="showMessage" :message="this.message" />
</transition>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to{
opacity: 0;
}
功能封装
功能基本实现了,但是发现Login里的东西冗余了。
首先,data里的showMessage和message,以及showToast函数多处地方都会用到。可以把它们抽离出来,再用mixin混入。
(我用的是vue2.x才需要弄mixin,vue3更简单一些)
在utils下新建一个toast.js。把刚刚提到的东西抽离出来
export default {
data() {
return {
showMessage: false,
message: "",
}
},
methods: {
showToast(msg, showTime) {
this.message = msg
this.showMessage = true
setTimeout(() => {
this.showMessage = false
}, showTime)
},
},
}
然后把Login页面toast相关的逻辑代码可以删了。
开头导入toast.js,并mixin一下
import useToast from "../utils/toast.js"
mixins: [useToast],
注册及注册校验
和登陆的逻辑基本一致。
加入了一个校验两次输入密码是否一致的功能。
在显示提示字符串的时候,下面的部分会被挤。
解决方法,提示字符串用一个div包裹,子绝父相。
<div class="login__alert">
<span>{{ infoMsg }} </span>
</div>
.login__alert {
position: relative;
span {
position: absolute;
left: 0;
top: 0;
}
}
避免自动填充
在input框中加入
autocomplete="off"