添加一个登录页面:
代码:
<template>
<div>
<van-form>
<van-nav-bar title="标题">van-nav-bar>
<van-cell-group>
<van-field v-model="user.mobile" placeholder="请输入手机号">
<template #left-icon>
<i class="iconfont icon-phone">i>
template>
van-field>
<van-field v-model="user.code" placeholder="请输入验证码">
<template #left-icon>
<i class="iconfont icon-lock1">i>
template>
<template #button>
<van-button class="codebtn" size="small" color="#ececec" round>获取验证码van-button>
template>
van-field>
van-cell-group>
<div class="loginbtn">
<van-button type="info" size="large">登录van-button>
div>
van-form>
div>
template>
<script>
export default {
data () {
return {
user: {
mobile: '', // 手机号
code: '' // 验证码
}
}
}
}
script>
<style lang="less" scoped>
.van-nav-bar.van-hairline--bottom {
background-color: #3596fa;
}
/deep/ .van-nav-bar__title.van-ellipsis {
color: #fff;
}
.codebtn {
.van-button__text{
color: #666;
}
}
.loginbtn {
margin: 20px;
.van-button {
border-radius: 10px;
}
}
style>
组成:
头部标题
使用 vant 中 navBar 组件 传送门
说明:
style
添加 scoped
属性:样式可以直接作用到 navBar
生成的结构中scoped
属性:样式无法作用到 navBar
生成的结构中了scoped
/deep/
scoped
属性的样式作用到生成的结构中/deep/
必须配置 less
语法来使用手机号 & 验证码输入框
使用 vant 中 field 组件 传送门
登录按钮
使用 vant 中的 button 组件 传送门
由于输入框之前有两个图标,在 vant 的图标库中没有这两个图标,为了解决这个问题 ,我们需要使用 iconfont 来加载这个图标
步骤:
- 在van-form中的vant-file中要设置一个rules属性,当在vant-file中输入完内容之后要校验输入内容 是否输入是否合法
//输入手机号的那个filed输入框
:rules="[{required:true,message:'请输入手机号'},{pattern:/^1[3456789]\d{9}$/,message:'手机号不合法'}]"
//输入验证码的那个filed输入框
:rules="[{required:true,message:'请输入验证码'}]"
- 点击登录按钮之后要对整个form表单进行校验,登录按钮也要写在
中
一旦点击按钮会优先校验van-form中表单元素是否满足rules的规则,不满足提示错误信息,
满足就触发van-form中的submit,做一些校验成功之后要做的事情,发送请求
步骤:
onSubmit
方法中得到要提交的参数 methods: {
// 点击登录按钮 校验成功之后要做的事情
async onSubmit () {
// 1.0发送请求
const res = await apiLogin(this.user)
console.log(res.data.data) // {token:xxx,refresh_token:xxx}
// 2.0登录成功保存token与refresh_token 到vuex跟localstorage中
this.$store.commit('setUserInfo', res.data.data)
setLocal('userInfo', res.data.data)
// 3.0登录成功跳转到首页
this.$router.push('/home')
}
}
步骤:
utils
目录下创建一个文件 myhttp.js
// 封装axios
// 1.0 导入axios
import axios from 'axios'
// 2.0 创建axios的实例
const http = axios.create({
// 设置基地址
baseURL: 'http://ttapi.research.itcast.cn'
// xsrfCookieName:这个不要这个属性,否则会跨域错误,后台没设置
})
// 3.0 给axios添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
})
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error)
})
// 4.0 将http暴露给外界
export default http
步骤:
api
目录下创建一个文件: use.js
myhttp.js
login/index.vue
中使用这个方法// 用来处理所有与用户相关的网络请求
// 导入自己封装好的axios实例
import http from '@/utils/myhttp'
// 1.封装登录的接口
function apiLogin (obj) {
return http({
method: 'post',
url: '/app/v1_0/authorizations',
data: obj
})
}
// 按需导出
export { apiLogin }
问题:在开发过程中我们进行网络请求之后,需要将处理的结果放到回调函数中处理,这样子会响应代码阅读性。
为了解决这样的问题:在 es 的新版本标识中出了一个新的技术: async & await
作用:
用法:
async
用来修饰异步代码所在的函数await
用来修饰异步代码await
修饰后的异步代码可以同步的方式来接收返回结果注意点:
步骤:
store
中 的 state
下创建一个属性: userInfo
store
中的 mutations
下创建一个方法: setUserInfo
userInfo
赋值store
中的 `userInfo // 2.0登录成功保存token与refresh_token 到vuex跟localstorage中
this.$store.commit('setUserInfo', res.data.data)
注意点:
localstorage
中import Vue from 'vue'
import Vuex from 'vuex'
// 导入存储数据到localStorage中的方法
import { getLocal } from '@/utils/mylocal'
Vue.use(Vuex)
export default new Vuex.Store({
state: { // 管理状态
// 在项目打开时应该从localStorage中取出来userInfo在vuex中
userInfo: getLocal('userInfo') || {}
},
mutations: { // 修改状态
// 定义一个setuserInfo的函数修改状态
setUserInfo (state, payload) {
// 给state里的userInfo赋值
state.userInfo = payload
}
}
})
步骤:
1.0 在 onSubmit
方法中添加逻辑:
localstorage
中 setLocal('userInfo', res.data.data)
2.0 在 store/index.js
中
在 state
下面的 userInfo
中添加代码:
userInfo: getLocal('userInfo') || {}
// 刷新数据vuex里的数据就没了,所以要在localStorage里面有数据的时候vuex也要有就把localStorage的数据拿出来就好
//下面这个是还没对localStorage进行操作方法的封装
//userInfo: JSON.parse(window.localStorage.getItem('userInfo')) || {}
由于将来我们会频繁的对 localstroage 进行操作, 我们可以将操作的步骤封装为一些单独的方法放到一个单独的文件中
步骤:
utils
下添加一个文件 mylocal.js
mylocal.js
文件中封装方法:
注意点:
// 封装对所有localStorage的操作
// 封装一个存储数据到localStorage中的方法
const setLocal = (key, value) => {
window.localStorage.setItem(key, JSON.stringify(value))
}
// 封装一个从localStorage中获取数据的方法
const getLocal = (key) => {
return JSON.parse(window.localStorage.getItem(key))
}
// 封装一个从localStorage中 删除数据的方法
const removeLocal = (key) => {
window.localStorage.removeItem(key)
}
// 导出
export { setLocal, getLocal, removeLocal }
登录时,网络可能比较慢,如果不作处理,用户会认为自己没有登录。会多次点击登录按钮。会额外的消耗服务器的性能。
任务:当用户点击一次登录之后,将登录按钮设置为加载状态。
准备知识点:
步骤:
loading
属性data
中设置一个 isLoding
属性,默认值为 false
onSubmit
时,将 isLoading
改为 true
isLoading
改为 false
onSubmit
时,判断 isLoading
是否为 false
,如果为 false
才能发送请求由于黑马头条接口在登录失败时直接返回一个 400,400 会将浏览器直接报错,无法正常执行后续的代码。要解决这个问题,可以使用 try-catch 来捕获错误
try-catch 的用法:
try {
// 可以会出错的代码
} catch (error) {
// 如果出错,就执行 catch 中的代码,
// 如果不出错,就不执行 catch 中的代码
// error: 指的就是出错的信息
}
try-catch 的作用:
methods: {
// 点击登录按钮 校验成功之后要做的事情
async onSubmit () {
// 进入是判断 isLoading是否为false,如果false说明目前还没有发送请求
if (this.isLoading === false) {
// 将加载状态设置为true
this.isLoading = true
try {
// 1.0发送请求
const res = await apiLogin(this.user)
this.isLoading = false
// console.log(res.data.data) // {token:xxx,refresh_token:xxx}
// 2.0登录成功保存token与refresh_token 到vuex跟localstorage中
this.$store.commit('setUserInfo', res.data.data)
setLocal('userInfo', res.data.data)
// 3.0登录成功跳转到首页
this.$router.push('/home')
} catch (error) {
console.log('出错了')
// 将loading动画不要
this.isLoading = false
// 添加一个失败的提示
this.$toast.fail('手机号或者验证码错误,请重新输入')
}
}
}
}
vant 中的提示框是 toast
提示失败:
Toast.fail('失败文案');
注意点: