前言
实战已经开始了!前面几篇文章已经将登录注册和模拟接口请求的内容讲完了,但是在登录失败或者接口请求失败的时候,还缺少一个提示内容,虽然浏览器也给我们提供了alert之类的提示框,但是作为前端开发,不仅为了美观,更加为了以后可以复用,所以我们可以写一个组件专门用来做提示弹窗信息的。
补充
在上一章节中,可能在调用接口的时候,URL写错了或者接口API写错了,都会导致错误信息,但是当我们用async/await去请求接口的时候,会发现并不会执行下面的else语句的。
👉 比如我们把baseURL中的fastmock写错成fastmock111
export const post = (url, data = {}) => { return new Promise((resolve, reject) => { axios.post(url, data, { baseURL: 'https://www.fastmock111.site/mock/eb925863ecc46f2108cd43d75f96c1cd/pro' }).then((response) => { resolve(response) }, err => { reject(err) }) }) } 复制代码
👉 然后我们再去请求post的时候,就会发现并不会提示登录失败
const handleLogin = async () => { const result = await post('/api/user/login', { mobile: data.mobile, password: data.password }) if (result.data.code === 0) { localStorage.isLogin = true router.push({ name: 'Home' }) } else { console.log('登录失败') } } 复制代码
点击登录之后,浏览器控制台就会直接报错了。对于async/await这种写法要怎么去控制接口请求报错呢?可以用js里面的try/catch方法。
const handleLogin = async () => { try { const result = await post('/api/user/login', { mobile: data.mobile, password: data.password }) if (result.data.code === 0) { localStorage.isLogin = true router.push({ name: 'Home' }) } else { console.log('登录失败') } } catch (e) { console.log('请求失败') } } 复制代码
虽然控制台还是有接口报错,但是同样也将提示信息告诉我们了,这样也就方便我们定位问题所在了。
Toast组件
🌀 在开发组件之前,我们需要去新建一个vue文件,但是这种公共的组件就不能直接新建在views目录下面了,还记得最初创建项目时,有一个components文件夹嘛?这里面就是用来存放公共组件的地方。
👉 在cpmponents文件夹下面新建一个Toast.vue
👉 Toast组件中的DOM结构和样式也比较简单
<template> <div class="toast">内容</div> </template> <script> export default { } </script> <style lang="scss" scoped> .toast{ position: fixed; top: 50%; left: 50%; transform: translate(-50%,-50%); padding: .1rem; background: rgba(0,0,0,0.5); border-radius: .05rem; color: #fff; } </style> 复制代码
👉 Login.vue中引入Toast组件
import Toast from '../../components/Toast' 复制代码
components: { Toast }, 复制代码
<Toast /> 复制代码
🔆 可以看到页面上就会直接显示出Toast了。
组件显隐
目前来看Toast组件是一直保持显示状态的,我们需要在点击登录之后才显示出来才行,并且间隔 2 秒之后自动隐藏。
👉 在setup函数中的data里面定义一个showToast,用于判断组件显示隐藏
const data = reactive({ showToast: false, }) 复制代码
👉 在Toast组件标签上通过v-if指令来判断showToast,为true的时候就显示,反之隐藏
<Toast v-if="data.showToast" /> 复制代码
👉 需要在handleLogin函数中请求接口失败时,将showToast设为true 👉 将showToast设为true的同时,需要用setTimeout方法将showToast在间隔 2 秒之后设为false
const handleLogin = async () => { try { const result = await post('/api/user/login', { mobile: data.mobile, password: data.password }) if (result.data.code === 0) { localStorage.isLogin = true router.push({ name: 'Home' }) } else { data.showToast = true console.log('登录失败') setTimeout(() => { data.showToast = false }, 2000) } } catch (e) { data.showToast = true console.log('请求失败') setTimeout(() => { data.showToast = false }, 2000) } } 复制代码
组件传参
在调用登录接口时,我们判断了登录失败和请求失败的逻辑,但是这些提示不应该直接用comsole.log输出到控制台,应该将提示语动态传递给Toast组件显示出来。
👉 在setup函数中的data里面定义toastMessage
const data = reactive({ showToast: false, toastMessage: '' }) 复制代码
👉 在Toast组件标签中使用toastMessage
<Toast v-if="data.showToast" :message="data.toastMessage" /> 复制代码
👉 Toast组件中通过props接收传递过来的message
export default { props: ['message'] } 复制代码
👉 将handleLogin方法中的console.log换成toastMessage
data.toastMessage = '请求失败' 复制代码
拆分组件
按照上面的代码来写的话,基本上是把所有的逻辑全部放在了一个setup函数里面,如果以后还要增加新的组件,那么这一个页面的代码量就又会很难维护了。而且也不符合compositionAPI中将逻辑归纳在一块区域的原则,所以我们需要拆分组件中的逻辑,也就是逻辑必须是跟随组件在一起的。
👉 打开Toast组件,将关于Toast组件逻辑全部放到一个新的方法中,然后通过export导出,可以让外部引入
export const useToastEffect = () => { const toastData = reactive({ showToast: false, toastMessage: '' }) const showToast = (message) => { toastData.showToast = true toastData.toastMessage = message setTimeout(() => { toastData.showToast = false toastData.toastMessage = '' }, 2000) } return { toastData, showToast } } 复制代码
- 逻辑部分和setup函数中写法一致,都是需要将绑定的数据定义在reactive中,最后通过return返回给外部。
👉 Login页面中不仅要引入Toast组件,还需要引入Toast的逻辑方法
import Toast, { useToastEffect } from '../../components/Toast' 复制代码
👉 setup函数中就可以直接使用Toast组件中的逻辑方法useToastEffect
setup () { const router = useRouter() const data = reactive({ username: '', password: '' }) const { toastData, showToast } = useToastEffect() const handleLogin = async () => { try { const result = await post('/api/user/login', { username: data.username, password: data.password }) if (result.data.code === 0) { localStorage.isLogin = true router.push({ name: 'Home' }) } else { showToast('登陆失败') } } catch (e) { showToast('请求失败') } } const handleRegisterClick = () => { router.push({ name: 'Register' }) } return { handleLogin, handleRegisterClick, data, toastData } } 复制代码
总结
本篇文章主要是将Toast组件进行封装,并把setup函数中关于Toast组件的部分全部拆分出来放到组件里面进行统一管理。