分析业务逻辑与页面渲染分离的好处 完成账号登录业务逻辑
在过去vue2的开发中,我们通常会把所有的业务逻辑和UI界面都在一个vue文件中去完成,导致了整个页面中代码逻辑过多,后期我们想复用这一部分的代码,可能需要花费大量的时间去提取,或者直接复制粘贴,导致大量的代码冗余的问题,所以我们为了避免这种问题,我们可以考虑在vue3中使用组合式API的方式,来抽离业务代码,使得业务代码和UI界面分离更容易维护、扩展和复用等。 大家想了解更多关于组合式API的问题可以去组合式 API 常见问答,里面详细的介绍了传统API和组合式API的区别和优劣势。
我们在pages/login文件夹下创建一个composables的组合式API的文件夹,用于存放我们login文件夹下所有的与业务相关的组合式API。 然后我们创建一个account-login.ts的文件用于编写我们的登录部分业务逻辑。如下:
import type { FormInst } from 'naive-ui'
import type { UserAccountLoginParams } from '~/api/user'
export const useAccountLogin = () => {
const formRef = ref<FormInst>()
const loading = ref(false)
const model = reactive<UserAccountLoginParams>({
username: null,
password: null,
})
const login = async () => {
}
return {
formRef,
loading,
model,
login,
}
}
我们写完这一部分后,会发现参数报错。是因为默认情况下我们的UserAccountLoginParams
不支持null类型所以我们需要给我们的类型添加一个null类型。如下:
在utils目录下创建一个types.ts的文件用于存放我们自己定义的通用类型。
export type IncludeNull<T> = T | null
调整api/user.ts中的类型:
import type { IncludeNull } from '~/utils/types'
export interface UserAccountLoginParams {
username: IncludeNull<string>
password: IncludeNull<string>
captcha?: IncludeNull<string>
}
export interface UserMobileLoginParams {
mobile: IncludeNull<string>
code: IncludeNull<string>
type: 'mobile'
}
调整完成后我们的报错也就随之消失了。 接下来我们来配置一下完善一下校验规则:
const rules = reactive<FormRules>({
username: [
{
required: true,
renderMessage: () => t('login.username.required'),
},
{
min: 5,
max: 20,
renderMessage: () => t('login.username.length'),
},
],
password: [
{
required: true,
renderMessage: () => t('login.password.required'),
},
{
min: 5,
max: 20,
renderMessage: () => t('login.password.length'),
},
],
})
最后return出去。 接下来我们来完善一下我们的登录接口:
// 1.加载loading状态
// 2.校验表单是否正确
// 3.请求接口
// 4.请求成功设置token
// 5.跳转到首页
const login = async () => {
loading.value = true
try {
await formRef.value?.validate()
await userStore.login(model)
loading.value = false
const redirect = router.currentRoute.value?.params?.redirect as string
await router.replace(redirect || '/')
}
catch (e) {
loading.value = false
}
}
接下来我们在项目中使用一下: 在pages/login/index.vue中使用:
<script lang="ts" setup>
const { rules, formRef, login, loading, model } = useAccountLogin()
</script>
<template>
<n-form ref="formRef" :model="model" :rules="rules" label-align="left" label-placement="left">
<n-form-item-row path="username">
<n-input v-model:value="model.username" :placeholder="$t('login.username.placeholder')">
<template #prefix>
<n-icon :component="UserOutlined" />
</template>
</n-input>
</n-form-item-row>
<n-form-item-row path="password">
<n-input v-model:value="model.password" type="password" show-password-on="click" :placeholder="$t('login.password.placeholder')">
<template #prefix>
<n-icon :component="LockOutlined" />
</template>
</n-input>
</n-form-item-row>
<n-form-item-row path="rememberMe">
<div class="w-100% flex items-center justify-between">
<n-checkbox v-model:value="model.rememberMe">
{{ $t('login.remember-me') }}
</n-checkbox>
<a class="cursor-pointer text-[var(--text-color-3)]">
{{ $t('login.forgot-password') }}
</a>
</div>
</n-form-item-row>
</n-form>
<n-button type="primary" :loading="loading" block secondary strong @click="login">
{{ $t('login.login') }}
</n-button>
</template>
测试是否可用