当前位置: 首页 > news >正文

用户中心Vue3项目开发2.0

目录

 一、网页实战

1.网页布局开发

2.顶部导航条的开发

Q:div区域内使用这样的布局可以实现什么样的效果?

导航条的功能实现:路由跳转

3.前端请求request

编写请求示例

4.全局用户管理

使用状态

二、页面开发

(一)用户登录界面

1.表单

2.用户点击登录后的操作

​编辑

(二)用户注册界面

(三)用户管理界面


 一、网页实战

1.网页布局开发

上中下最基础最简单网页布局

<a-layout><a-layout-header>Header</a-layout-header><a-layout-content>Content</a-layout-content><a-layout-footer>Footer</a-layout-footer></a-layout>

footer底部栏最好开发

中间content的内容是需要我们动态替换的,需要引入vue-router库,我们的项目中已经有了router目录,打开index.ts文件,修改我们需要配置的路由

<template><div id="basicLayout"><a-layout><a-layout-header class="header"><GlobalHeader /></a-layout-header><a-layout-content class="content"><router-view /></a-layout-content><GlobalFooter /></a-layout></div>
</template>

2.顶部导航条的开发

把全局顶部导航栏GlobalHeader单独定义到组件component目录中

这是antdesignvue中的一个组件示例

<template><a-menu v-model:selectedKeys="current" mode="horizontal"><a-menu-item key="mail"><template #icon><mail-outlined /></template>Navigation One</a-menu-item><a-menu-item key="app" disabled><template #icon><appstore-outlined /></template>Navigation Two</a-menu-item><a-sub-menu><template #icon><setting-outlined /></template><template #title>Navigation Three - Submenu</template><a-menu-item-group title="Item 1"><a-menu-item key="setting:1">Option 1</a-menu-item><a-menu-item key="setting:2">Option 2</a-menu-item></a-menu-item-group><a-menu-item-group title="Item 2"><a-menu-item key="setting:3">Option 3</a-menu-item><a-menu-item key="setting:4">Option 4</a-menu-item></a-menu-item-group></a-sub-menu><a-menu-item key="alipay"><a href="https://antdv.com" target="_blank" rel="noopener noreferrer">Navigation Four - Link</a></a-menu-item></a-menu>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { MailOutlined, AppstoreOutlined, SettingOutlined } from '@ant-design/icons-vue';
export default defineComponent({setup() {const current = ref<string[]>(['mail']);return {current,};},components: {MailOutlined,AppstoreOutlined,SettingOutlined,},
});
</script>

按需修改后,再全局布局basicLayout中引入globalheader组件直接看效果即可

{key: "/",icon: () => h(HomeOutlined),label: "系统主页",},{key: "/user/login",icon: () => h(LoginOutlined),label: "用户登录",},{key: "/user/register",icon: () => h(UserAddOutlined),label: "用户注册",},{key: "/admin/manage",icon: () => h(TeamOutlined),label: "用户管理",},{key: "about",icon: () => h(InfoCircleOutlined),label: "其他信息",children: [{key: "help-center",label: "帮助中心",},{key: "contact-us",label: "联系我们",},{key: "privacy-policy",label: "隐私政策",},],},

实际效果图如下所示

系统主页的左侧还需要插入一个网站logo和网站名

左边中间右边逐步完善导航条

Q:div区域内使用这样的布局可以实现什么样的效果?

 <a-row><a-col flex="300px"><!--网站图标and网站名--></a-col><a-col flex="auto"><!--网站菜单--></a-col><a-row flex="100px"><!--登录注册按钮--></a-row></a-row>

导航条的功能实现:路由跳转

点击不同的菜单项跳转到不同的页面,切换路由

如何配置路由?

项目中所有可以跳转的页面都是在index.js中定义的

path代表用户访问的路径,component代表进入页面所对应加载的组件,name命名相关即可

{path: "/",name: "home",component: HomePage,},

页面最基础的就包括:用户登录页面(权限等级:普通用户)、用户注册页面(权限等级:普通用户)、用户管理页面(权限等级:管理员)

@click和函数双向绑定,点击key可以实现路由跳转

定义变量来获取路由对象(按alt+回车引入),使用useRouter,引入钩子函数获取一个路由跳转器

const router = useRouter();

使用路由跳转器的push方法确定要跳转的页面

刷新页面时,需要监听路由变化,更新当前菜单选中状态

const router = useRouter(); // 菜单栏路由跳转
const current = ref<string[]>(["home"]);
router.afterEach((to) => {//current是vue的响应式变量,更新.value值current.value = [to.path];//要去的页面
});

简单来说就是从 url——>导航条的选项——>页面显示的内容 要一一对应

点击导航栏的用户登录,URL显示xxx/user/login,实际页面也为登录页,这些都是基于vueRouter实现的

const routes: Array<RouteRecordRaw> = [{path: "/",name: "home",component: HomePage,},{path: "/user/login",name: "userLogin",component: UserLoginPage,},{path: "/user/register",name: "userRegister",component: UserRegisterPage,},{path: "/admin/manage",name: "adminManage",component: UserManagePage,},
];

思考:如何实现统一配置路由和菜单项?重复的path代码是否可以合并?

3.前端请求request

动态获取用户的登录信息,向后端发送请求,后端执行操作并响应给前端

前端负责界面展示和动态交互,避免写很复杂的逻辑

如何发送请求:传统我们用ajax,当下主流请求工具库axios(封装库、简化)

在src目录下新建文件request.ts

以下是axios的使用案例

const instance = axios.create({baseURL: 'https://some-domain.com/api/',timeout: 1000,headers: {'X-Custom-Header': 'foobar'}
});
// 添加请求拦截器
axios.interceptors.request.use(function (config) {// 在发送请求前做些什么return config;}, function (error) {// 对请求错误做些什么return Promise.reject(error);});// 添加响应拦截器
axios.interceptors.response.use(function (response) {// 对响应数据做些什么(状态码在2xx范围内会触发)return response;}, function (error) {// 对响应错误做些什么(状态码超出2xx范围会触发)return Promise.reject(error);});

因为是发送请求,所以肯定需要有一个接收方,这里需要一个后端项目配合。

注意如果前后端都在同一台电脑上运行注意端口port冲突,可以在package.json文件中加上--port=3000强制修改前端运行端口

  "scripts": {"serve": "vue-cli-service serve --port=3000","build": "vue-cli-service build","lint": "vue-cli-service lint"},

编写请求示例

前端要发很多的请求,对应调用后端多个接口:用户注册、用户登录、用户管理等等

在src下新建api包用来存放接口文件,用户中心主要运用到的是用户类接口,不妨新建一个user.ts文件,模块化更利于维护

注意request.ts文件最后要export default myAxios;然后我们在user.ts中引入myAxios实例import myAxios from "@/request";

编写示例接口的注意点:

  • 注意函数需要导出在其他项目文件中才能使用

  • 请求包括URL地址、请求方法类型大多一致

  • post请求使用data传递参数

  • get请求可以直接传参,或者使用params传参

export const userLogin = async (params: any) => {return myAxios.request({url: "/myapp/user/login",method: "POST",data: params,});
};

最后一共需要用户注册、用户登录、用户注销、获取当前用户、获取用户列表、删除用户这些接口,其中用户删除接口需要注意:后端把long id作为一个完整的json对象。

还有需要注意的是前端端口3000和后端端口不一致会导致跨域报错,有几种解决跨域的方法

最简单的就是在后端UserController中加入注解

@CrossOrigin(origins={"http://loaclhost:3000"},allowCredential="true")

4.全局用户管理

核心:每一个页面都可以获取当前用户的登录信息

全局变量:适合所有页面全局共享的变量不局限于一个页面中

选择pinia这个主流的全局状态管理库,在功能上类似vuex

定义 Store | Pinia

在项目入口main.ts文件中引入pinia

什么是状态?store是保存状态和业务逻辑的实体,如loginUserStore,可以选择组合式api的写法

在src下新建store目录存储所有需要使用的状态,我们先把登录用户的用户名设置为“未登录”,然后根据需要获取或更新当前用户的值,创建函数fetchLoginUser,调用后端getCurrentUser方法获取到返回值(使用await才是获取到值不然就是一个promise变量)

  • Promise 是 JavaScript 中用于处理异步操作的特殊对象,它代表一个尚未完成但预期将来会完成的操作的最终结果(可能是成功值或失败原因)。

    • Promise 有三种状态:

      • pending(进行中):初始状态

      • fulfilled(已成功):操作成功完成

      • rejected(已失败):操作失败

根据返回值且是否获取到了用户的详细信息进行判断,再给store里的loginUser赋值,即 loginUser.value = res.data.data;

获取到了用户信息还需要一个对用户信息进行设置的函数setLoginUser,用于接收新的用户信息loginUser.value = newLoginUser;

总结:如何定义变量、获取变量、改变变量?就像就是一个get和set方法

import { defineStore } from "pinia";
import { ref } from "vue";
import { getCurrentUser } from "@/api/user";export const useLoginUserStore = defineStore("loginUser", () => {const loginUser = ref<any>({userAccount: "未登录",// userPassword: "null",});// const loading = ref(false);// const error = ref<string | null>(null);// 远程获取用户信息async function fetchLoginUser() {try {const res = await getCurrentUser();console.groupCollapsed("[fetchLoginUser] 完整响应详情");console.log("响应状态:", res.status);console.log("响应数据:", res.data);console.log("数据结构:", res.data.data ? "嵌套格式" : "扁平格式");console.groupEnd();if (res.data.code === 0 && res.data.data) {loginUser.value = res.data.data;console.log("[fetchLoginUser] 更新后的loginUser:", loginUser.value);} else {console.warn("[fetchLoginUser] 无用户数据返回");}} catch (error) {console.error("[fetchLoginUser] 获取用户信息失败:", error);throw error;}}// 设置用户信息(接收一个新的用户信息)function setLoginUser(newLoginUser: any) {loginUser.value = newLoginUser;}return {loginUser,fetchLoginUser,setLoginUser,};
});

使用状态

在app.vue文件中引入loginUserStore,进入主页时会全局获取用户信息,在任意页面都可以使用这个信息。

可以在globalheader中先引入store后再在登录按钮旁使用

{{JSON.stringify(loginUserStore.loginUser)}}

或者先在div中进行v-if的判断如果获取到了用户id就展示store中的loginUser的username,如果没有获取到用户名就设置为“未知用户”

<div class="user-login-status"><div v-if="loginUserStore.loginUser.id">{{loginUserStore.loginUser.userAccount || "登录用户-请设置用户昵称"}}</div><div v-else><a-button type="primary" href="/user/login">登录</a-button><a-button href="/user/register">注册</a-button></div>
</div>

二、页面开发

功能上:用户登录、用户注册、用户管理

新建pages目录,存放页面,比views命名上更像

新建homePage.vue文件

按照url的层级对pages目录进行进一步的分层,homepage为第一层,新建user目录,第二层里存放登录注册页面,新建admin目录,存放管理页面,记得为每个页面分配不同的div-id

记得修改index.ts中对应的组件部分

(一)用户登录界面

1.表单

表单样式:https://2x.antdv.com/components/form-cn/#Form-

<template><div id="userLoginPage"><div id="loginSection"><h2>用户登录</h2><a-form:model="formState"name="basic":label-col="{ span: 6 }":wrapper-col="{ span: 18 }"autocomplete="off"@finish="handleSubmit"><a-form-itemlabel="账户"name="userAccount":rules="[{ required: true, message: '请输入账户名!' }]"><a-inputv-model:value="formState.userAccount"placeholder="请输入用户名"/></a-form-item><a-form-itemlabel="密码"name="userPassword":rules="[{ required: true, message: '请输入密码!' }]"><a-input-passwordv-model:value="formState.userPassword"placeholder="请输入密码"/></a-form-item><!-- <a-form-item name="remember" :wrapper-col="{ offset: 8, span: 16 }"><a-checkbox v-model:checked="formState.remember">记住我</a-checkbox></a-form-item> --><a-form-item :wrapper-col="{ offset: 8, span: 16 }"><a-button type="primary" html-type="submit">登录</a-button></a-form-item></a-form></div></div>
</template>

定义接口

  • reactive 函数:Vue 3 的响应式 API,会将普通对象转换为响应式对象

  • 泛型 <FormState>:指定该响应式对象必须符合 FormState 接口类型

  • 初始值:

    • 字符串字段初始化为空字符串(""

    • 布尔值字段被注释,若启用默认值为 true

interface FormState {// 接收用户输入的变量userAccount: string;userPassword: string;// remember: boolean;
}const formState = reactive<FormState>({// 接收用户输入的变量userAccount: "",userPassword: "",// remember: true,
});

对登录表单进行美化:(要点)居中布局,合适的行距,提高用户的体验(用户思维)

2.用户点击登录后的操作

通过handlesubmit函数:需要引入store和router

根据表单提交的用户名和密码

// 提交表单后的逻辑处理
const handleSubmit = async (values: any) => {try {const res = await userLogin(values);if (res.data.code === 0 && res.data.data !== null) {await loginUserStore.fetchLoginUser();message.success("登录成功");router.push({ name: "home", replace: true });} else {message.error("登录失败: 账号或密码错误"); // 更明确的错误提示}} catch (error) {console.error("请求异常:", error); // 捕获网络或服务器错误message.error("请求失败,请检查网络");}

user.ts文件里的userLogin异步函数,根据返回码和是否获取到了用户数据

/*** 用户登录* @param params*/
export const userLogin = async (params: any) => {return myAxios.request({url: "/myapp/user/login",method: "POST",data: params,});
};
网页登录时的交互流程图

(二)用户注册界面

用户登录页面的基础上再加一个确认密码的表单,总而言之就是改造

注册成功后跳转到登录页面,对前端注册页面进行一些初步的校验,虽然主要还是依靠后端

一些报错可以结合上报错信息和报错描述

注册界面成品图如下

(三)用户管理界面

注意这个仅管理员可见

这个页面像是对数据库表格选择性的美化

对于antdesignvue我们可以选择必要的

<template><a-table :columns="columns" :data-source="data"><template #name="{ text }"><a>{{ text }}</a></template><template #customTitle><span><smile-outlined />姓名</span></template><template #tags="{ text: tags }"><span><a-tagv-for="tag in tags":key="tag":color="tag === 'loser' ? 'volcano' : tag.length > 5 ? 'geekblue' : 'green'">{{ tag.toUpperCase() }}</a-tag></span></template><template #action="{ record }"><span><a>邀请 一 {{ record.name }}</a><a-divider type="vertical" /><a>删除</a><a-divider type="vertical" /><a class="ant-dropdown-link">更多操作<down-outlined /></a></span></template></a-table>
</template><script lang="ts">
import { SmileOutlined, DownOutlined } from '@ant-design/icons-vue';
import { defineComponent } from 'vue';const columns = [{dataIndex: 'name',key: 'name',slots: { title: 'customTitle', customRender: 'name' },},{title: '年龄',dataIndex: 'age',key: 'age',},{title: '地址',dataIndex: 'address',key: 'address',},{title: '标签',key: 'tags',dataIndex: 'tags',slots: { customRender: 'tags' },},{title: '操作',key: 'action',slots: { customRender: 'action' },},
];const data = [{key: '1',name: '张三',age: 32,address: '北京市朝阳区一号湖公园',tags: ['优秀', '开发'],},{key: '2',name: '李四',age: 42,address: '上海市浦东新区一号湖公园',tags: ['待提升'],},{key: '3',name: '王五',age: 32,address: '广州市天河区一号湖公园',tags: ['资深', '教师'],},
];export default defineComponent({setup() {return {data,columns,};},components: {SmileOutlined,DownOutlined,},
});
</script>

总之写前端页面缺啥就去组件库里翻一翻可以大幅提高开发效率。

http://www.lryc.cn/news/581703.html

相关文章:

  • 2048小游戏实现
  • 线性代数--AI数学基础复习
  • 深度学习6(多分类+交叉熵损失原理+手写数字识别案例TensorFlow)
  • Chunking-free RAG
  • Web-API-day2 间歇函数setInterval与事件监听addEvenListener
  • 【Note】《Kafka: The Definitive Guide》第四章:Kafka 消费者全面解析:如何从 Kafka 高效读取消息
  • Apache Spark 4.0:将大数据分析提升到新的水平
  • A O P
  • 金融级B端页面风控设计:操作留痕与异常预警的可视化方案
  • 深度学习篇---深度学习常见的应用场景
  • 容声W60以光水离子科技实现食材“主动养鲜”
  • [Qt] visual studio code 安装 Qt插件
  • FastAPI + Tortoise-ORM + Aerich 实现数据库迁移管理(MySQL 实践)
  • 深度学习 必然用到的 线性代数知识
  • 嵌入式 数据结构学习(五) 栈与队列的实现与应用
  • React Ref 指南:原理、实现与实践
  • 【PyTorch】PyTorch中torch.nn模块的卷积层
  • 零基础,使用Idea工具写一个邮件报警程序
  • Solidity——什么是状态变量
  • 计算机网络:(七)网络层(上)网络层中重要的概念与网际协议 IP
  • Kafka “假死“现象深度解析与解决方案
  • UI前端大数据可视化进阶:交互式仪表盘的设计与应用
  • 数据驱动实时市场动态监测:让商业决策跑赢时间
  • 【LeetCode 热题 100】240. 搜索二维矩阵 II——排除法
  • 黑马点评系列问题之实战篇02短信登录 利用资料中的mysql语句创建数据表时报错
  • 关于 栈帧变化完整流程图(函数嵌套)
  • Java 双亲委派机制笔记
  • QML 使用QtObject定义私有变量
  • 基于Flask和机器学习开发的米其林餐厅数据可视化平台
  • 单片机:STM32F103的开发环境搭建