
一、前言
前面我们已经完成了基础的整合工作,接下来开始具体业务的开发了,因为是个人项目,全干工程师,所以无论你从哪里开始都可以,我习惯从登录开始,前后端一起,先写页面,再写接口,然后调试,一个功能做完再开始下一个。这只是我个人习惯,你完全可以随性一点,先写后端再写前端,或者前端全部用静态数据,写完再写后端对接接口。
二、登录界面开发
每次开始写前端的时候都会很纠结,脑子里全是想法,但是落实到具体页面又不知道从哪下手。首先 UI 从何而来就让人头大。经过这么多年的折腾,有了一些小的经验,分享给大家。
- 找个类似产品,直接照抄,抄的肯定比你一边做一边想要好的多,最终成品也更像一个产品
早年的时候,我会有一点心理负担,觉得这样不太道德,也不屑于这么做,觉得靠自己设计出来的才是最完美。其实不然,术业有专攻,我们的思想早已经被同质化,如果凭借我们自己发挥,最终也还是会和我们见过的
UI贴近,左边菜单,右边展示页面,在一些小样式上挣扎,最后花费大量时间。所以还不如直接放下心理包袱,直接借鉴,等完整产品出来后,再去打磨,调整出自己的风格。
- 寻找专业的UI设计师设计
当然个人开发最理想的情况是找到志同道合的设计师朋友一起合作,或者直接去某平台花钱买设计
- 在一些设计平台找一些公开的设计作品
这里我目前用的比较多的是 即时设计 ,这个项目我也打算在这个上面找一找。js.design/
在资源广场搜索即可,找到自己中意的即可。


2.1. 页面编写
这个具体怎么实现我就不赘述了,照着 UI 界面模仿即可。
这里有两个问题:
第一:登录的窗口应该小一点,登录成功之后跳转到主页面,窗口变大。
第二:登录窗口应该锁死不允许收缩,全屏等操作,主界面可以拖动放大缩小,并且可以全屏。
带着这两个问题我结合 AI,去官方文档找了一下解决方案。
如果你时间比较充裕,我希望你可以自己先探索研究一下,过程很有趣。
下面介绍具体实现方式:
开发开发前,先将之前的测试代码全部清除。 顺便引入一下
tailwindcss,参考文档:tailwind.nodejs.cn/docs/instal...
❗️注意: 在我开发完登录模块后,我发现 Ant Design Vue 使用起来很不顺手,可能是功能太强大了,做的太灵活了,我决定换成 Naive UI , 我平时用的比较多的其实还是 Element Plus ,但是我想要尝试一下其他的。如果你习惯于 Ant Design Vue 那就接着使用即可。www.naiveui.com/
2.2. 切换 Naive UI 组件库
- 安装依赖
bash
pnpm i -D naive-ui
- 字体
bash
pnpm i -D vfonts
- 图标库/图标包装组件
bash
npm i -D @vicons/antd @vicons/utils
- 配置按需自动导入
typescript
import AutoImport from 'unplugin-auto-import/vite'
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'
export default defineConfig({
// ...
plugins: [
// ...
AutoImport({
resolvers: [NaiveUiResolver()],
}),
Components({
resolvers: [NaiveUiResolver()],
}),
],
})
- 修改 request 中的 message 方法
这里需要注意,Naive UI 的
message如果要在setup外使用需要需要额外处理一下。www.naiveui.com/zh-CN/os-th...
创建 src/hooks/useMessagehook.ts
typescript
import { createDiscreteApi } from 'naive-ui'
const { message, notification, dialog, loadingBar, modal } = createDiscreteApi(
['message', 'dialog', 'notification', 'loadingBar', 'modal']
)
export { message, notification, dialog, loadingBar, modal }
request 中改为使用 hooks 方法。
typescript
import { message } from '../hooks/useMessagehook'
...
message.error(msg)
2.3. 首页开发
创建 src/view/login/LoginPage.vue
html
<script setup lang="ts">
import { useUserInfoStore } from '../../stores/modules/user'
import { UserOutlined, LockOutlined } from '@vicons/antd'
import router from '../../router'
interface LoginFormData {
username: string
password: string
}
// 登录表单数据
const loginFormData = reactive<LoginFormData>({
username: 'admin',
password: 'admin123456',
})
// 登录表单ref
const loginFormRef = ref()
// 加载动画
const loading = ref(false)
// 获取用户信息缓存仓库
const userStore = useUserInfoStore()
// 表单验证规则
const rules = ref({
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
})
// 登录
const handleLogin = async () => {
// 表单验证
const valid = await loginFormRef.value?.validate()
// 校验不成功直接 return
if (!valid) {
return false
}
// 校验成功进行后续操作
// 1.加载 loading
loading.value = true
// 2.登录请求 获取token
userStore
.login()
.then(() => {
// 跳转
router.push('/')
})
.catch(() => {
// 验证失败,重新加载验证码
})
.finally(() => {
// 验证结束,隐藏loading
loading.value = false
})
}
</script>
<template>
<div class="h-screen">
<n-grid class="h-full">
<n-gi span="14">
<div class="relative h-full bg-[url('../../images/login_bg.webp')] bg-center bg-cover bg-no-repeat">
<span class="absolute top-5 left-5 text-2xl font-bold text-white"> EZ-ADMIN </span>
<span class="absolute bottom-30 left-1/2 -translate-x-1/2 text-xl text-nowrap text-white">
相信自己我能行, 老天不会辜负你所付出的努力!
</span>
</div>
</n-gi>
<n-gi span="10">
<div class="h-full flex flex-col items-center justify-center px-15">
<div class="text-3xl font-bold text-black text-center">欢迎登录</div>
<div class="w-full flex items-center justify-center flex-nowrap gap-1 my-5">
<!-- 分割线:更细腻的设计 -->
<div class="w-16 h-px bg-slate-400"></div>
<span class="text-nowrap text-slate-400">账号密码登录</span>
<div class="w-16 h-px bg-slate-400"></div>
</div>
<!-- 表单 -->
<n-form
class="w-50 sm:w-50 md:w-75 lg:w-90"
:show-label="false"
ref="loginFormRef"
:model="loginFormData"
:rules="rules"
size="large"
>
<n-form-item path="username">
<n-input v-model:value="loginFormData.username" placeholder="请输入用户名">
<template #prefix>
<n-icon :component="UserOutlined" class="text-slate-400" />
</template>
</n-input>
</n-form-item>
<n-form-item path="password">
<n-input
v-model:value="loginFormData.password"
show-password-on="mousedown"
type="password"
placeholder="请输入密码"
>
<template #prefix>
<n-icon :component="LockOutlined" class="text-slate-400" />
</template>
</n-input>
</n-form-item>
<n-form-item>
<n-button block type="primary" size="large" @click="handleLogin">登 录</n-button>
</n-form-item>
</n-form>
</div>
</n-gi>
</n-grid>
</div>
</template>
<style scoped lang="less"></style>

这里简单提一下,页面写好后要配置好路由,以及路由出口。
在
tauri.conf.json中定义初始打开窗口的大小。
typescript"app": { "windows": [ { "title": "tauri-app", "width": 800, "height": 600 } ], "security": { "csp": null } },
三、总结
因为其实最终还是 web 那一套,所以我直接沿用了之前开发的一套脚手架项目,不过为了寻求一些变化,我这次使用了 Tailwindcss 和 Naive UI 。 原项目地址:github.com/Caoshenyang...
千里之行,始于足下。你的"个人公司"从这第一个2小时开始。欢迎在评论区分享你的进展或遇到的卡点,我会逐一查看,尽可能的帮助解决。我们下一篇文章见!