其三:登陆&注册部分开发

布局

页面其实很简单,照着画就行了。登陆和注册的页面基本一致,可以写好一个复制一份。

逻辑

先来理一下假登陆注册的逻辑吧。

  1. 无论用户输入什么,只要点击登陆按钮就算登陆成功,跳转到Home页。
  2. 无论用户输入什么,只要点击注册按钮,就算注册成功,跳转到登陆页。
  3. 点击“立即注册”,跳转到注册页。
  4. 点击“已有账号去登陆”,跳转到登陆页。
  5. 登陆后,无法再回到登陆页面(无论是通过按钮、回退还是改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。

vue 不用elementui手写描述列表 vue怎么写app_字符串

但是刷新一次就可以恢复正常。

我的解决方法是,用路由守卫判断是否有上一个页面,有的话就刷新。没有(因为reload()和go(0)都是强制刷新,刷新后就没有上一个页面)的话就什么都不做。

beforeRouteEnter(to, from, next) {
		next(() => {
			if (from.name) {
				location.reload()
			}
		})
	},

或者给登陆里的style加上scoped。。。

使用模拟接口实现登陆

使用fastmock模拟一个假的接口

vue 不用elementui手写描述列表 vue怎么写app_ios_02

使用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"