需要用到Vant的Field组件
1.views下新建一个注册页面 ,完成基本布局。引入Vue和Field并使用。
2.在官方文档中搜索,查看自己需要的内容,将其直接粘贴到页面中。
3.给注册页面添加一个单独的路由,注册页面不需要底部。(注意,相关样式需要引入不同的组件,请细心查看官方文档,按需拿取内容)
4. 利用计算属性给输入框做条件判断。本案例以手机号为例。
<template>
<div class="container">
<header class="header">注册header>
<div class="content">
<van-field
v-model="username"
placeholder="请输入手机号"
clearable
:error-message="usernamemsg"
/>
<van-field
v-model="password"
type="password"
clearable
placeholder="请输入密码"
error-message="密码格式错误"
/>
<van-field
v-model="code"
center
clearable
placeholder="请输入短信验证码"
error-message="验证码格式错误"
>
<van-button slot="button" size="small" type="primary">发送验证码van-button>
van-field>
div>
div>
template>
<script>
import Vue from 'vue'
import { Field, Button } from 'vant'
Vue.use(Field)
Vue.use(Button)
export default {
data () {
return {
username: '18813007814',
password: '123456',
code: ''
}
},
computed: {
usernamemsg () {
if (this.username === '') {
return ''
} else if (!/^[1][3,4,5,7,8][0-9]{9}$/.test(this.username)) {
return '手机号码格式错误'
} else {
return ''
}
}
}
}
script>
注:在此之前,记住要先去路由页面添加一个注册页面的路由。
1.补充了密码以及验证码的计算属性判断
密码:如果为空返回空,如果不符合正则,返回格式错误,否则表示可以直接返回空
验证码:如果为空返回空,否则不为五位,返回验证码格式错误,否则成功返回空
2.验证码
3.验证码跟接口做交互
在setCode最后定义一个getCode函数,在下方定义该函数(类似面向对象写法)。
定义getCode:
4.引入一个按钮,作为注册按钮
定义register函数
1.判断:
2.当上面的判断都通过,再定义真正的注册函数
<template>
<div class="container">
<header class="header">注册头部header>
<div class="content">
<van-field
v-model="tel"
placeholder="请输入手机号"
:error-message="usertel"
clearable
/>
<van-field
v-model="password"
type="password"
placeholder="请输入密码"
:error-message="pass"
clearable
/>
<van-field
v-model="sms"
center
clearable
placeholder="请输入短信验证码"
:error-message="test"
>
<van-button :disabled="flag" slot="button" size="small" type="primary" @click="sendCode">{{ buttonmsg }}van-button>
van-field>
<van-button type="primary" :loading="loading" loading-text="注册..." size="large" :disabled="zhud" @click="register">注册van-button>
<van-divider @click="toLogin">去登录van-divider>
div>
div>
template>
<script>
import Vue from 'vue'
import { Field,Button,Toast,Divider } from 'vant'
import axios from 'axios'
Vue.use(Field)
Vue.use(Button)
Vue.use(Toast)
Vue.use(Divider)
export default {
data () {
return {
tel:'',
password:'',
sms:'',
buttonmsg:'点击发送验证码',
flag:false,
adminCode:'',
zhud:false,
loading:false
}
},
computed: {
usertel () {
if (this.tel === ""){
return ''
}else if(!/^[1][3,4,5,7,8][0-9]{9}$/.test(this.tel)){
return '手机号格式错误'
}else {
return ''
}
},
pass () {
if (this.password === ""){
return ''
}else if(this.password.length<6){
return '密码不可小于6位'
}else {
return ''
}
},
test () {
if (this.sms === ""){
return ''
}else if(this.sms.length !== 5){
return '验证码格式错误'
}else {
return ''
}
}
},
methods: {
toLogin () {
this.$router.replace('/login')
},
sendCode () {
let time = 4
let timer
timer = setInterval(()=>{
time --
if(time === 0){
clearInterval(timer)
this.flag=false
this.buttonmsg = '点击发送验证码'
return
}
this.flag = true
this.buttonmsg = time + '秒后重新发送'
},1000)
this.getCode()
},
getCode () {
if(!/^[1][3,4,5,7,8][0-9]{9}$/.test(this.tel) || this.tel===""){
Toast('手机号码输入有误')
}else{
axios.get('https://www.daxunxun.com/users/sendCode?tel='+this.tel).then(res=>{
if(res.data === 1){
Toast('用户名已注册,请更改')
}else if(res.data === 0){
Toast('获取验证码失败')
}else{
this.adminCode = res.data.code
console.log(this.adminCode)
}
})
}
},
register () {
if (this.tel === '' || this.usertel === '手机号码格式错误') {
Toast('手机号码输入有误')
return
}
if (this.password === '' || this.pass === '密码格式错误,最少为6位') {
Toast('密码输入有误')
return
}
if (this.sms === '' || this.sms !== this.adminCode) {
Toast('验证码输入有误')
return
}
this.reallR()
},
reallR () {
this.zhud=true
this.loading=true
axios.post('https://www.daxunxun.com/users/register', {
username: this.tel,
password: this.password
}).then(res=>{
this.zhud=false
this.loading=false
if (res.data === 2) {
Toast('用户名已注册,请直接登录')
} else if (res.data === 0) {
Toast('注册失败')
} else {
Toast('注册成功')
}
})
}
}
}
script>
页面布局以及基本逻辑同注册基本相同,可直接复制注册,将相关注册字样更改为登录。删除相关的判断。更改相关函数。
<template>
<div class="container">
<header class="header">注册头部header>
<div class="content">
<van-field
v-model="tel"
placeholder="请输入手机号"
:error-message="usertel"
clearable
/>
<van-field
v-model="password"
type="password"
placeholder="请输入密码"
:error-message="pass"
clearable
/>
<van-button type="primary" :loading="loading" loading-text="登录..." size="large" :disabled="zhud" @click="login">登录van-button>
<van-divider @click="toRegister">去注册van-divider>
div>
div>
template>
<script>
import Vue from 'vue'
import { Field,Button,Toast,Divider} from 'vant'
import axios from 'axios'
// import { setInterval, clearInterval } from 'timers';
// import func from '../../../vue-temp/vue-editor-bridge';
Vue.use(Field)
Vue.use(Button)
Vue.use(Toast)
Vue.use(Divider)
export default {
data () {
return {
tel:'',
password:'',
zhud:false,
loading:false
}
},
computed: {
usertel () {
if (this.tel === ""){
return ''
}else if(!/^[1][3,4,5,7,8][0-9]{9}$/.test(this.tel)){
return '手机号格式错误'
}else {
return ''
}
},
pass () {
if (this.password === ""){
return ''
}else if(this.password.length<6){
return '密码不可小于6位'
}else {
return ''
}
}
},
methods: {
toRegister () {
this.$router.replace('/register')
},
login () {
if (this.tel === '' || this.usertel === '手机号码格式错误') {
Toast('手机号码输入有误')
return
}
if (this.password === '' || this.pass === '密码格式错误,最少为6位') {
Toast('密码输入有误')
return
}
if (this.sms === '' || this.sms !== this.adminCode) {
Toast('验证码输入有误')
return
}
this.reallR()
},
reallR () {
this.zhud=true
this.loading=true
axios.post('https://www.daxunxun.com/users/login', {
username: this.tel,
password: this.password
}).then(res=>{
this.zhud=false
this.loading=false
if (res.data === 2) {
Toast('用户未注册')
} else if(res.data === -1){
Toast('密码错误')
}else if (res.data === 0) {
Toast('登录失败')
} else {
Toast('登录成功')
localStorage.setItem('isLogin','ok') //登录标识
this.$router.back() //登陆成功返回上一页
}
})
}
}
}
script>
除了登陆路由,其他页面都需要登录验证。
router.beforeEach((to,from,next)=>{
// console.log(to)
// console.log(from)
// next() //至此就可以显示页面了
//做业务逻辑,如果是登录状态,就进行下一步(注意登录页面不可做这个判断)
if(to.name = 'login'){ //如果要去的页面是登录页面,就进行下一步,不做判断
next()
}else{
if(localStorage.getItem('isLogin')==='ok'){
next()
}else{
next('/login')
}
}
路由独享的导航守卫—一般不推荐直接使用
比如在购物车路由下方加入下面一段代码,可以实现购物车页面的相关判断。
没有登录状态就直接去到登录页面,有登录状态就继续下一步。
beforeEnter (to,from,next) {
if(localStorage.getItem('isLogin')==="ok"){
next()
}else{
next('/login')
}
}
先来简单看一下组件内的导航守卫相关介绍:
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。
不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
beforeRouteEnter (to, from, next) {
next(vm => {
// 通过 `vm` 访问组件实例
})
}
本文以购物车页面为例,在路由进入之前,做一个判断,有登录状态进行下一步,没有登录状态就直接去到登录页面。组件内的导航守卫有两张写法,请看案例,且不同写法有不同的效果,按需而定。
<template>
<div class="container">
<header class="header">购物车头部</header>
<div class="content">购物车内容</div>
</div>
</template>
<script>
export default {
beforeRouteEnter (to,from,next) {
// if (localStorage.getItem('isLogin')==='ok'){
// next()
// }else{
// next('/login') //这种登陆成功返回点击购物车之前的页面
// }
next(vm => {
if (localStorage.getItem('isLogin')==='ok'){
next()
}else{
// next('./login')
vm.$router.push('/login') //这种登录成功直接返回到了购物车
}
})
}
}
</script>
基本思路:在离开页面前将内容高度存储到本地,在返回页面后在去本地获取并设置内容高度。
2.修改App.vue中路由的显示部分
3.在离开首页时,记录滚动条的位置,返回时滚动到该位置即可,下方案例有一句代码是为了实现其他业务需求,可以忽略不看。
4.利用keepAlive,可以在activated中进行返回后的操作,设置内容高度为本地存储的值。
对于导航守卫还需要补充一些相关知识,上面步骤执行完会发现个人中心存在一些问题。当在个人中心页面显示已经登录时,无法后退。
通过vue开发者工具,我们可以观察到,当我们未登录时,先去到首页,再去到个人中心,此时个人中心应该是未登录页面(/user/nologin),我们点击登录,会去到登录页面,点击登录后,在开发者工具中,我们会看到,我们先到了个人中心的未登录页面,再去到了个人中心的已登录页面,并且每次后退,都是先后退到个人中心未登录页面,又跳转到个人中心登录页面。(因为未登录页面有一个判断,所以我们每次点击后退,在视觉上感觉无法后退,实际上是退回到了未登录页面,这个页面又做了个判断,又回到已登录页面,如此循环往复。)
解决:
执行完以上解决方法,发现我们可以后退了,但是,需要后退两次才能返回主页。通过开发者工具我们可以看到页面路由跳转的流程,见下图:
相关原因以及解决方法:
1.在路由文件中将重定向删除。
2.个人中心未登录页面到登录页面的跳转是声明式挑战,需要更改为编程式跳转。在编程式跳转中,运用replace方法()
3.在个人中心页面,我们之前用的是beforeRouteEnter,如果是该页面下的其它页面做跳转,此方法无法触发。所以我们此处应该将该方法替换成侦听属性。(侦听属性可以侦听路由的变化,打印可以获取相关的路由,因此我们可以做判断。)
4.但是我们发现侦听属性在别的页面跳转到该页面时,第一次不会触发监听。因此第一次监听还是需要用到beforeRouteEnter,再此方法中也需要用到replace,至此可以解决问题了。
步骤详情
1.在路由文件中,将个人中心页面的重定向删除
2.在nologin页面将路由守卫删去,改变登录跳转方式。在个人中心的login页面,直接将业务逻辑删去。
3.个人中心页面,将beforeRouteEnter中的next改为replace方法。(因为没有重定向,默认跳转为/user替换为/user/login或者/user/nologin)在下面利用侦听属性侦听路由的变化,并做判断。 (replace和push页面显示不同)
<template>
<div class="container">
<header class="header">个人中心头部header>
<div class="content">
<router-view>router-view>
个人中心内容
div>
div>
template>
<script>
export default {
beforeRouteEnter (to, from, next) {
next(vm => {
if (localStorage.getItem('isLogin') === 'ok') {
// 因为没有重定向,默认跳转为 /user 替换为/user/loging
vm.$router.replace('/user/loging')
} else {
vm.$router.push('/user/nologin')
}
})
},
watch: {
$route (val) {
console.log(val)
if (localStorage.getItem('isLogin') === 'ok') {
this.$router.replace('/user/loging')
} else {
this.$router.replace('/user/nologin')
}
}
}
}
script>