实战已经开始了!前面几篇文章已经将登录注册和模拟接口请求的内容讲完了,但是在登录失败或者接口请求失败的时候,还缺少一个提示内容,虽然浏览器也给我们提供了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('登录失败')
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ahJMxbLN-1658392764352)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/23ae703e9dca4373bca1eaf705bee115~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?)]
点击登录之后,浏览器控制台就会直接报错了。对于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('请求失败')
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JnQHok65-1658392764353)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5a261a6a32e040d49115642245789bc4~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?)]
虽然控制台还是有接口报错,但是同样也将提示信息告诉我们了,这样也就方便我们定位问题所在了。
🌀 在开发组件之前,我们需要去新建一个vue文件,但是这种公共的组件就不能直接新建在views目录下面了,还记得最初创建项目时,有一个components文件夹嘛?这里面就是用来存放公共组件的地方。
👉 在cpmponents文件夹下面新建一个Toast.vue
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XrkMVuka-1658392764354)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e7c90a8141ca49838a67abfefa9e1f40~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?)]
👉 Toast组件中的DOM结构和样式也比较简单
内容
👉 Login.vue中引入Toast组件
import Toast from '../../components/Toast'
components: {
Toast
},
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pXbf6vJ1-1658392764354)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/47a645fc9b054dabaeb54251956502b3~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?)]
🔆 可以看到页面上就会直接显示出Toast了。
目前来看Toast组件是一直保持显示状态的,我们需要在点击登录之后才显示出来才行,并且间隔 2 秒之后自动隐藏。
👉 在setup函数中的data里面定义一个showToast,用于判断组件显示隐藏
const data = reactive({
showToast: false,
})
👉 在Toast组件标签上通过v-if指令来判断showToast,为true的时候就显示,反之隐藏
👉 需要在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)
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G5V0EZm4-1658392764354)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/47190ffd6f84428b96d65d5fce28618d~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?)]
在调用登录接口时,我们判断了登录失败和请求失败的逻辑,但是这些提示不应该直接用comsole.log输出到控制台,应该将提示语动态传递给Toast组件显示出来。
👉 在setup函数中的data里面定义toastMessage
const data = reactive({
showToast: false,
toastMessage: ''
})
👉 在Toast组件标签中使用toastMessage
👉 Toast组件中通过props接收传递过来的message
export default {
props: ['message']
}
👉 将handleLogin方法中的console.log换成toastMessage
data.toastMessage = '请求失败'
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a8qI8JU1-1658392764354)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3f9f45a309a54a2f9101cd8976253a48~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?)]
按照上面的代码来写的话,基本上是把所有的逻辑全部放在了一个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 }
}
👉 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组件的部分全部拆分出来放到组件里面进行统一管理。