持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天
登录模块进阶
前面我们做了一个比较基础的登录 UI,现在我们再来给他增加一些常用的功能及业务流。
基础登录完善
登录模块我们通常会选择 UI 框架的表单组件(比如EP的el-form、el-form-item)搭配输入框和按钮(el-input、el-button)作为基架。既能帮助我们美化页面元素(方便地引入图标),又能帮助我们提升用户的体验(数据编辑的便捷性)。
图标加入
el-input组件的prefix-icon属性与show-password属性remixicon图标库使用useRenderIcon图标渲染hook
这时候你可能会觉得这个输入框显得有点小气了,我们利用el-form的size属性将表单整体放大一些。
是不是好看多了 ~
验证码
验证码我们可以插入输入框中,即使用el-input的插槽,将图形验证码组件ReImageVerify插入(组件详解后续会编写)。
<Motion :delay="200">
<el-form-item>
<el-input
clearable
placeholder="验证码"
:prefix-icon="
useRenderIcon('ri:shield-keyhole-line', { online: true })
"
>
<template v-slot:append>
<ReImageVerify v-model:code="imgCode" />
</template>
</el-input>
</el-form-item>
</Motion>
这里提一嘴组件声明的问题:我们在对自己封装的组件添加
name标识的时候,需要在.vue 文件中定义两个script标签,一个用来定义组件的name,一个用来编写组件逻辑。我想你肯定跟我一样,是不太能接受这种有点“多此一举”的写法的。不过我想找个问题vue官方应该会在后续解决掉的,这里我们使用一个大佬开发的插件来帮我们解决找个问题。
unplugin-vue-define-options 插件
安装
pnpm install unplugin-vue-define-options -D
在 vite 中引入
我们的项目时 TS 项目,所以也需要同时适配tsconfig.json
{
"types": [
"node",
"vite/client",
"element-plus/global",
"unplugin-vue-define-options"
]
}
使用
<script setup lang="ts">
defineOptions({
name: "test",
});
</script>
如果你想要封装一个组件库,那么这个插件就会很有用了......
然后我们来看一下效果
发现样式好像不太对,应该把两边的padding去掉。这是EP自带的默认样式,所以我们需要打开浏览器控制台,找到对应的样式并修改——使用:deep来实现。
<style lang="scss" scoped>
:deep(.el-input-group__append, .el-input-group__prepend) {
padding: 0;
}
</style>
多渠道登录
其他渠道登录包括:
- 手机登录
- 二维码登录
- 第三方登录:微信、支付宝、QQ、微博等
常用的 ReIcon 组件 Bug
看一下效果:
我们发现第三方登录的内容不见了?怎么回事?仔细看,其中我们使用了IconifyIconOnline组件,是它没有生效,而且我们发现这个组件在浏览器中是红色的。
我们先来看看这个红色
TS找不到这个类型,无法为我们做提示,所以我们需要给它做个全局声明
我们把这个组件引入login代码中看看
发现,生效了,这是为什么呢?既然引入才有效,说明这个组件不是全局组件呢。像这种可能频繁用到的组件,我不想每次都手动引入,怎么办呢?
这不就回到了组件的全局注册吗
一般来说,我们不会把每个组件都全局注册(除非你在做组件库),多数情况下我们会进行手动引入自己封装的组件,因为用的不频繁。所以我们有必要单独为全局组件做处理。
在src/components文件下新建一个全局组件注册文件registerGlobComp.ts
// 全局注册的组件 src\components\registerGlobComp.ts
import type { App } from "vue";
import { withInstall } from "/@/utils/withInstall";
import iconifyIconOnline from "./ReIcon/src/iconifyIconOnline";
export const IconifyIconOnline = withInstall(iconifyIconOnline);
export function registerGlobComp(app: App) {
app.use(IconifyIconOnline);
}
main.ts中再引入,并时刻保持写注释的习惯哦!大功告成!
表单验证
首先我们要明确的是,我们应该遵循EP的表单规则做验证,并捋清楚相关要点。
- 确定需要做验证的表单:通过
ref拿到表单DOM元素,在rules属性中填充配置规则 - 确定需要做验证的表单选项:表单(
prop)与输入框数据(v-model)绑定,以协助验证 - 制定验证规则:一般规则、
validator规则(规则的制定我们另起文件utils.rule.ts编写,再引入)
其他的表单开发如手机登录、忘记密码、注册基本和登录相同,这里就不再描述,大家可以自行查看源码。
二维码组件问题
项目中该组件使用了tsx语法开发,所以我们需要让项目支持tsx语法。
官方推荐我们使用@vue/babel-plugin-jsx插件来支持jsx/tsx语法,但是我们使用的是Vite,就不是用这个插件啦。应使用官方提供的@vitejs/plugin-vue-jsx插件,它提供了Vue 3特性的支持,包括 HMR、全局组件解析、指令和插槽。
pnpm install @vitejs/plugin-vue-jsx -D
然后在我们的vite插件文件中引入即可
登录操作
一个方法就可以描述清楚基本的登录的逻辑
const onLogin = async (formEl: FormInstance | undefined) => {
loading.value = true; // 登录loading激活
if (!formEl) return; // 确定是表单登录
// 表单数据规则验证
await formEl.validate((valid, fields) => {
if (valid) {
// 模拟请求(实际会在这里执行一个登录请求,一般请求成功后返回info数据)
setTimeout(() => {
loading.value = false; // 登录loading取消
// 将登录成功返回的info数据存入session
storageSession.setItem("info", {
username: "admin",
accessToken: "eyJhbGciOiJIUzUxMiJ9.test",
});
// 根据info信息,初始化项目路由(路由权限控制)
initRouter("admin").then(() => {});
ElMessage.success("登陆成功"); // 优化体验
router.push("/"); // 登录成功后跳转到指定路由
}, 2000);
} else {
loading.value = false; // 登录loading取消
return fields;
}
});
};
登录表单切换
各个表单之间的切换由currentPage来控制,每次点击都会将currentPage的值改变,并存入store中。
- 0: 登录表单
- 1: 手机号登陆表单
- 2: 二维码登陆表单
- 3: 注册表单
- 4: 忘记密码表单
效果示例:
注册表单: