系列文章目录
本系列记录一下通过Abp搭建后端,Vue+Element UI Plus搭建前端,实现一个小型项目的过程。
- Day 1 Vue 页面框架
- Day 2 Abp框架下,MySQL数据迁移时,添加表和字段注释
- Day 3 登录页以及路由 (一)
- Day 4 登录页及路由 (二)Vue状态管理
- Day 5 登录页及路由 (三) 基于axios的API调用
文章目录
目录
系列文章目录
文章目录
前言
一、整体布局
二、登录窗体
三、API 调用修改
总结
前言
还是走到了这一步,要涉足我的盲区,样式和布局了。先看看最终的效果:
一、页面需求
这是一个非常非常简单的登录页,基本功能如下:
1. 提供账号密码输入框
2. 输入框左侧显示图标
3. 账号可以一键清空
4. 密码可以查看明文
5. 账号不能为空;密码不能为空,密码长度6-12位
6. 重置按钮清空输入的账号密码
7. 登录按钮调用api,成功后转到/home/index,失败则弹出失败消息。
一、整体布局
登录视图中,背景为统一颜色 #2b4b6b,非常好记的一个颜色值。然后整体居中。这个居中是通过视频中的方法,先绝对定位,然后左上点到正中央,再平移回去,这个思路对于居中只知道 text-align的我而言就友好多了。
具体布局如下:
src/views/login/LoginView.vue
<template><div class="login_container"><div class="login_box"><div class="logo_box"><img src="@/assets/logo.svg" alt="logo" /></div></div></div>
</template>
<style lang="less" scoped>
.login_container {background-color: #2b4b6b;height: 100%;
}
.login_box {width: 430px;height: 300px;background-color: white;position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);border-radius: 3px;.logo_box {height: 100px;width: 100px;position: absolute;left: 50%;transform: translate(-50%, -50%);border-radius: 50%;border: 1px solid #ddd;padding: 10px;box-shadow: 0 0 10px;background-color: #eee;img {height: 100%;width: 100%;border-radius: inherit;background-color: #eee;}}
}
</style>
这里基本上都是跟着视频走,用的less,还没有看到和普通css有啥区别,另外,好像element ui plus用的是sass。后续有时间了再看看。
上述代码渲染出来的效果是这样的:
就是一个图标,盖在一个白色矩形上。这个白色矩形,就是后续的输入窗体了。
二、登录窗体
输入窗体直接用el-form,这里提一下和视频不一样的地方,就是图标的自动导入。在前面已经配置好了自动导入,所以不用像视频那样手动引入,直接在代码里写就可以。
在components.d.ts中,会自动生成如下代码:
其它的基本上就是根据ElementUI Plus的官方文档来处理了。包括输入框、校验、事件处理,官方文档上都有说明,基本就是CV大法就可以了。
src/views/login/components/LoginForm.vue
<template><el-form ref='loginFormRef' :model='loginForm' :rules='rules' class='login_form' label-width="0"><el-form-item prop="username"><el-input v-model="loginForm.username" class="w-50 m-2" placeholder="账号" clearable><template #prefix><ElIcon><ElIconUser></ElIconUser></ElIcon></template></el-input></el-form-item><el-form-item prop="password"><el-input v-model="loginForm.password" class="w-50 m-2" type="password" placeholder="密码" show-password><template #prefix><ElIcon><ElIconLock></ElIconLock></ElIcon></template></el-input></el-form-item><el-form-item><div class="login_buttons"><el-button type="primary" class="justify-end" @click="submitForm(loginFormRef)">登录</el-button><el-button class="justify-end" @click="resetForm(loginFormRef)">重置</el-button></div></el-form-item></el-form>
</template>
三、API 调用修改
需要特别说明的就是登录API调用了。昨天已经做了一个简单处理,但是实际上还是需要再修改一下。
修改主要提现在两点,错误处理和响应数据统一处理。
错误处理又分为两个地方,axios的响应拦截器和login方法里面。上代码:
src\api\index.ts
http.interceptors.response.use((response: AxiosResponse) => {const { data } = responsereturn data},async (error: AxiosError) => {if (error.code == AxiosError.ERR_BAD_RESPONSE) {error.message = '服务器错误!请您稍后重试'}if (error.code == AxiosError.ECONNABORTED) {error.message = '请求超时!请您稍后重试'}if (error.code == AxiosError.ERR_NETWORK) {error.message = '网络错误!请您稍后重试'}const result = {code: error.code,message: error.message,success: false}return result }
)
在响应拦截器中,做了两个处理,第一个就是正常返回时,把data直接返回;第二个就是错误时,针对特定code,添加了中文消息,然后将错误封装成统一响应数据。
然后在调用的地方,也做了相应的修改
src\api\login.ts
主要是针对异常做了处理,具体errorToResult方法如下:
export const errorToResult = (error: unknown) => {const axError = error as AxiosErrorreturn {code: axError ? (axError.code ? axError.code : '-1') : '-1',success: false,message: axError ? (axError.message ? axError.message : '') : error + '',data: null}
}
那为什么要这么做?
首先在调用axios时,会有各种各样的可能出错,那么login方法就需要去try-catch,所以这里的异常处理是必不可少的。
另外,后端返回的结果,会有定义code,根据code不同,会有不同的处理方式,而这个又是和业务紧密相关的,并不是一个统一弹窗就能完全覆盖的。当然,一些基础的错误用统一弹窗也就够了。
总体思路就是在login这里,把所有的异常处理掉,统一成一致的响应数据,然后在实际使用的地方,根据响应数据再进行后续处理。
最后,在LoginForm中,实际调用的代码是这个样子的:
const submitForm = async (formEl: FormInstance | undefined) => {if (!formEl) returnawait formEl.validate(async (valid, fields) => {if (valid) {await doLogin()}})
}const currentUser = useCurrentUserStore()
const router = useRouter()const doLogin = async () => {const result = await login(loginForm)handleResultDTO(result,(r: ResultDTO<Login.LoginResponse>) => {const { data } = rcurrentUser.setToken(data!.token)currentUser.setUserInfo({ name: data!.nickname })router.push('/home/index')})// if (result.success && result.data) {// const loginResponse = result.data// currentUser.setToken(loginResponse.token)// currentUser.setUserInfo({ name: loginResponse.nickname })// router.push('/home/index')// } else {// ElMessage.error(result.message)// }
}
在 doLogin中,注释掉的内容后面被封装到 handleResultDTO方法里:
export const handleResultBase = (result: ResultBase, action: (r: ResultBase) => any): any => {if (result && result.success) {return action(result)} else {ElMessage.error(result.message)}
}export const handleResultDTO = <T>(result: ResultDTO<T>, action: (r: ResultDTO<T>) => any): any => {if (result && result.success && result.data) {return action(result)} else {ElMessage.error(result.message)}
}
这个只是两种不同的写法,本质上都是依据响应数据是否返回了正确了结果来处理,提取成方法只是一个习惯。
总结
以上就是今天的内容,本文记录了一下vue登录页面的具体搭建过程,另外对API调用进行了重构,主要是涉及到异常处理部分。