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

小白系列Vite-Vue3-TypeScript:011-登录界面搭建及动态路由配置

前面几篇文章我们介绍的都是Vite+Vue3+TypeScript项目中环境相关的配置,接下来我们开始进入系统搭建部分。本篇我们来介绍登录界面搭建及动态路由配置,大家一起撸起来......

搭建登录界面

登陆接口api

项目登陆接口是通过mockjs前端来模拟的

模拟服务接口LoginApi

首先在src/mock文件夹下新建login.ts文件,模拟两个服务接口(验证码获取+用户登录)

import { MockMethod } from 'vite-plugin-mock';export const LoginApi: Array<MockMethod> = [{url: '/api/captchaImage',method: 'get',response: () => {return {msg: 'OK',img: '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',code: 200,uuid: '37e7a189a9b14be6a5cbae80af43abaa',};},},{url: '/api/login',method: 'post',response: () => {return {msg: 'OK',code: 200,token:'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6Ijc2YzYzNzczLWY2ZWEtNDlkMC05MDIyLTg4ZmUxNjI1NmMzNyJ9.XUeTaH-VZu_Mm0Rm1m_lST4YH1-ovX5Gg9w_Z4nA04agzxzeTdb5XxKCIhMr8pPatCKmiCql9E7afMY96oGYfQ',};},},
];

LoginApi引入

修改src/mock文件夹下的index.ts文件,添加内容如下

import { LoginApi } from './login';
const mock: Array<MockMethod> = [...LoginApi];

创建登录API

在src/api文件夹下新建login.ts文件,创建获取验证码接口captchaImage和用户登录api接口login

import request from '@/utils/request';export const captchaImage = () => {return request.get('/api/captchaImage');
};
export const login = () => {return request.post('/api/login');
};

登录界面Login.vue

在src/views路径下新建Login.vue文件,这个文件就是我们的登录界面文件

<template><div class="login-main"><el-form ref="ruleFormRef" :model="ruleForm" status-icon :rules="rules" label-width="120px" class="ruleForm"><el-form-item prop="user"><el-input :prefix-icon="User" v-model="ruleForm.user" clearable /></el-form-item><el-form-item prop="pass"><el-input :prefix-icon="Lock" v-model="ruleForm.pass" type="password" /></el-form-item><el-form-item prop="code"><el-input :prefix-icon="Lock" v-model="ruleForm.code" class="code-value" /><img :src="img" alt="" class="code-img"></el-form-item><el-form-item><el-button type="primary" @click="submitForm(ruleFormRef)">登录</el-button><el-button @click="resetForm(ruleFormRef)">重置</el-button></el-form-item></el-form></div>
</template><script setup lang='ts'>
// 方法引入
import { reactive, ref, onMounted } from 'vue'
import router from '@/router';
import { setLocalStorage } from "@/utils/localstorage";
import type { FormInstance } from 'element-plus'
// 组件引入
import { User, Lock } from '@element-plus/icons-vue'
// 接口引入
import { captchaImage, login } from "@/api/login";onMounted(() => {captchaImage().then(datas => {console.log(datas)img.value = 'data:image/gif;base64,' + datas.imguuid.value = datas.uuid})
})
let img = ref<any>("")
let uuid = ref<string>("")
const ruleFormRef = ref<FormInstance>()
const validateUser = (rule: any, value: any, callback: any) => {if (value === '') {callback(new Error('用户名不能为空'))} else {callback()}
}
const validatePass = (rule: any, value: any, callback: any) => {if (value === '') {callback(new Error('密码不能为空'))} else {callback()}
}
const validateCode = (rule: any, value: any, callback: any) => {if (value === '') {callback(new Error('验证码不能为空'))} else {callback()}
}
const ruleForm = reactive({user: 'wangjianlei',pass: '123456',code: '4'
})const rules = reactive({pass: [{ validator: validatePass, trigger: 'blur' }],user: [{ validator: validateUser, trigger: 'blur' }],code: [{ validator: validateCode, trigger: 'blur' }],
})const submitForm = (formEl: FormInstance | undefined) => {if (!formEl) returnformEl.validate((valid) => {if (valid) {login().then(res => {console.log(res)setLocalStorage("LH_TOKEN", res.token)router.push("/")}).catch(err => {throw new Error(err);})} else {return false}})
}const resetForm = (formEl: FormInstance | undefined) => {if (!formEl) returnformEl.resetFields()
}
</script><style lang="scss" scoped>
.login-main {display: flex;padding: 25px;.ruleForm {width: 500px;.code-value {width: 260px;}.code-img {margin-left: 10px;width: 75px;height: 30px;}}
}
</style>

配置动态路由

动态路由接口

项目动态路由接口同样是通过mockjs前端来模拟的

模拟服务接口HomeApi

首先在src/mock文件夹下新建home.ts文件,模拟动态路由返回服务接口

import { MockMethod } from 'vite-plugin-mock';export const HomeApi: Array<MockMethod> = [{url: '/api/routerList',method: 'get',response: () => {const routes = [{path: '/main/PageOne',name: 'PageOne',component: 'PageOne.vue',},{path: '/main/PageTwo',name: 'PageTwo',component: 'PageTwo.vue',},{path: '/main/PageThree',name: 'PageThree',component: 'PageThree.vue',},];return {msg: 'OK',code: 200,data: routes,};},},
];

这里我们可以看到共返回了三个路由“PageOne”,“PageTwo”和“PageThree”。

HomeApi引入

修改src/mock文件夹下的index.ts文件,添加内容如下

import { MockMethod } from 'vite-plugin-mock';
import { HomeApi } from './home';
import { LoginApi } from './login';const mock: Array<MockMethod> = [...LoginApi, ...HomeApi];export default mock;

创建动态路由API

在src/api文件夹下新建home.ts文件,创建获取动态路由接口GetDynamicRoutes

import request from '@/utils/request';export const GetDynamicRoutes = () => {return request.get('/api/routerList');
};

新增路由界面

根据我们利用mockjs模拟的动态路由接口返回的数据,在src/views文件夹下创建modules文件夹,新建PageOne.vue,PageTwo.vue和PageThree.vue界面文件。

动态路由配置

我们的动态路由数据应由一个公共的地方进行管理,所以呢这里我选择利用vue的状态管理器pinia来实现这个功能。

首先我们在pinia的state中添加一个路由项routes(RouteRecordRaw类型的数组):

state: (): storeHome => {return {//路由表routes: [],};
},

然后在action中还需要添加一个根据路由数据加载动态路由的方法(updateRoutes),方法所需的路由数据和router对象由外部传入。(这里用外部传入router是为了避免循环调用router,毕竟需要进行加载动态路由的地方基本都有个router的示例对象,而外部传入的话,只需要调用然后传入一次router就可以了)

在src/store/type/home.ts添加状态项routes类型定义:

import { RouteRecordRaw } from 'vue-router';export type storeHome = {routes: Array<RouteRecordRaw>;
};

加载路由的思路其实也很简单,首先解析咱调用接口后传入的路由数据,根据路由的数据类型生成对应的路由表,并存储到pinia中,然后直接遍历这个pinia中的路由表,使用router.addRoute()方法将路由加载进去。router.addRoute()方法支持传如两个参数,方便我们在指定位置的路由中插入children,这种情况下第一个参数是父级路由的name,第二个参数就是要添加的children路由对象。

需要我们注意的是:vite使用动态路由,在动态导入路由组件的时候,需要特别注意不能将页面路径直接作为component导入,虽然开发环境一般是能正常加载,但是打包到生产环境的时候十有八九会报错,所以我们需要添加以下代码:

//根据自己项目实际目录结构组织,注意这里的“../../”不能用“@”别名代替
let modules = import.meta.glob('../../views/modules/*.vue');

然后用modules形式引入,完整动态路由的pinia代码如下:

import { defineStore } from 'pinia';
import { storeHome } from '../types/home';let modules = import.meta.glob('../../views/modules/*.vue');export const useHomeStore = defineStore('index', {state: (): storeHome => {return {//路由表routes: [],};},getters: {},actions: {updateRoutes(data: Array<any>, router: any) {this.routes = [];data.forEach((el) => {this.routes.push({path: el.path,name: el.name,component: modules[`../../views/modules/${el.component}`],});});this.routes.forEach((el) => {router.addRoute('Home', el);// router.addRoute();});},},
});

加载动态路由

上面我们已经配置好了路由接口和加载路由的方法,加载动态路由的思路也很简单,在我们的初始页面中调用路由的数据接口,在获取到数据之后调用加载的方法即可。

// 方法引入
import router from '@/router';
// 接口引入
import { GetDynamicRoutes } from "@/api/home"
// 状态管理器引入
import { useHomeStore } from "@/store/modules/home";const homeStore = useHomeStore()
onBeforeMount(() => {if (!getLocalStorage("LH_TOKEN")) {router.push("/login")} else {alert("登陆成功")GetDynamicRoutes().then(res => {homeStore.updateRoutes(res.data, router)})finish.value = true}
})

为验证我们的路由是否被加载成功,我们可以在调用动态路由同时创建对应的按钮,以便我们进行路由跳转。

<el-button v-for="item in routes" :key="item.name" @click="handleClick(item.path)">{{ item.name }}</el-button>const routes = computed(() => homeStore.routes)
// 路由按钮点击事件
const handleClick = (path: string) => {router.push(path)
}

完整页面代码如下:

<template><div class="home-main" v-if="finish"><div><el-button v-for="item in routes" :key="item.name" @click="handleClick(item.path)">{{ item.name }}</el-button></div><RouterView /></div></template>
<script setup lang='ts'>
// 方法引入
import { reactive, ref, onBeforeMount, onMounted } from 'vue'
import { computed } from "@vue/reactivity";
import { getLocalStorage } from '@/utils/localstorage'
import router from '@/router';
// 组件引入
import HomeHeader from './home/HomeHeader.vue';
// 接口引入
import { GetDynamicRoutes } from "@/api/home"
// 状态管理器引入
import { useHomeStore } from "@/store/modules/home";const homeStore = useHomeStore()
onBeforeMount(() => {if (!getLocalStorage("LH_TOKEN")) {router.push("/login")} else {alert("登陆成功")GetDynamicRoutes().then(res => {homeStore.updateRoutes(res.data, router)})finish.value = true}
})
const routes = computed(() => homeStore.routes)
// 路由按钮点击事件
const handleClick = (path: string) => {router.push(path)
}
let finish = ref(false)
</script>
<style lang="scss" scoped>
.home-main {}
</style>

动态路由效果

配置路由守卫

其实截止上面,我们的动态路由已经加载成功了。不过仔细测试会发现,还会有一个问题bug,假如我们刷新跳转后的页面,或者直接使用动态路由的路径进行跳转,就会出现报错“no match found for location with path '/PageOne' ”。添加的动态路由失效了,页面也没有显示,这是因为我们的路由和状态管理器pinia在刷新之后都会被重置,而我们加载路由的方法是在系统初始页面被调用的,当我们直接F5刷新页面或者直接输入路由路径的时候,初始页面其实并没有被加载,也就是说我们的动态路由并没有被加载上去,自然这个动态的页面也就丢失了。

这里我们可以通过添加路由守卫的方式来解决这个问题,大致思路:假如我们的页面请求路径不是我们定义的初始路径的时候,我们就在路由守卫中要求在跳转之前先去查询状态管理器中是否存在我们的动态路由,或者该动态路由是否满足我们的初始页面跳转要求,若不满足则请求动态路由接口并加载我们的动态路由,在加载完成后再继续执行页面跳转操作。

路由守卫代码如下:

// 路由守卫
router.beforeEach((to, from, next) => {if (to.path !== '/main' && to.path !== '/') {const store = useHomeStore();if (store.routes.length < 1) {GetDynamicRoutes().then((res) => {store.updateRoutes(res.data, router);next({ path: to.path, replace: true });}).catch((_) => {next();});} else {next();}} else {next();}
});

最终效果

至此,登录界面和动态路由基本搭建就完成了。

我相信,每天学习一点点,收获成长亿点点!

相关文章:

小白系列Vite-Vue3-TypeScript:011-登录界面搭建及动态路由配置

前面几篇文章我们介绍的都是ViteVue3TypeScript项目中环境相关的配置&#xff0c;接下来我们开始进入系统搭建部分。本篇我们来介绍登录界面搭建及动态路由配置&#xff0c;大家一起撸起来......搭建登录界面登陆接口api项目登陆接口是通过mockjs前端来模拟的模拟服务接口Login…...

C语言( 缓冲区和重定向)

一.缓冲输入&#xff0c;无缓存输入 while((chgetchar()) ! #) putchar(ch); 这里getchar(),putchar()每次只处理一个字符&#xff08;这里只是知道就好了&#xff09;&#xff0c;而我们使用while循环&#xff0c;当读到#字符时停止 而看到输出例子&#xff0c;第一行我们输入…...

编程思想、方法论和架构的类型及应用

概要编程思想是指在编写代码时所采用的基本思维方式和方法论。分类编程思想编程思想为软件开发提供了思维范式和指导思路&#xff0c;例如面向对象思想、函数式编程思想等&#xff0c;它们帮助程序员更好地抽象问题、组织代码、提高代码复用性和可维护性&#xff0c;包括一下几…...

【OA办公】OA流程审批大揭秘,带你看遍所有基础流程

流程审批&#xff0c;是所有企业的OA办公系统重要组成部分&#xff0c;是任何OA办公系统都不可缺少的。比起传统的纸张传阅、签批的审批模式浪费了大量的时间和成本&#xff0c;因此越来越多的企业采用OA这种全新的、高效的、智能的审批模式。流程审批除了这些好处&#xff0c;…...

《零基础入门数据结构与算法》专栏介绍

目录 前言 第一部分&#xff1a;重点 第二部分&#xff1a;题库 第三部分&#xff1a;测试 第四部分&#xff1a;实验 第五部分&#xff1a;试卷 总结 前言 本专栏主要分为五个部分&#xff1a; ① 重要知识点详解 ② 近百道练习题解析 ③ 数据结构与算法章节测试 …...

测试开发之Django实战示例 第九章 扩展商店功能

第九章 扩展商店功能在上一章里&#xff0c;为电商站点集成了支付功能&#xff0c;然后可以生成PDF发票发送给用户。在本章&#xff0c;我们将为商店添加优惠码功能。此外&#xff0c;还会学习国际化和本地化的设置和建立一个推荐商品的系统。本章涵盖如下要点&#xff1a;建立…...

【Spring】一文带你吃透AOP面向切面编程技术(下篇)

个人主页&#xff1a; 几分醉意的CSDN博客_传送门 上节我们介绍了什么是AOP、Aspectj框架的前置通知Before传送门&#xff0c;这篇文章将继续详解Aspectj框架的其它注解。 文章目录&#x1f496;Aspectj框架介绍✨JoinPoint通知方法的参数✨后置通知AfterReturning✨环绕通知Ar…...

【java】Spring Boot --40 个 Spring Boot 常用注解(建议收藏)

本文目录一、Spring Web MVC 注解Spring Web MVC 注解RequestMappingRequestBodyGetMappingPostMappingPutMappingDeleteMappingPatchMappingControllerAdviceResponseBodyExceptionHandlerResponseStatusPathVariableRequestParamControllerRestControllerModelAttributeCross…...

《游戏学习》| 微信对话模拟生成器源码分析

简介微信对话生成器&#xff0c;是一款在线微信聊天对话制作的工具&#xff0c;它可以设置苹果或安卓状态栏&#xff0c;包括手机电量、手机时间等&#xff0c;还可以设置不同用户的角色&#xff0c;然后发送文字、语音、红包、转账等多种好玩的功能&#xff0c;可谓是一款娱乐…...

剑指 Offer 10- I. 斐波那契数列[c语言]

目录题目思路代码结果该文章只是用于记录考研复试刷题题目 力扣斐波那契数列 写一个函数&#xff0c;输入 n &#xff0c;求斐波那契&#xff08;Fibonacci&#xff09;数列的第 n 项&#xff08;即 F(N)&#xff09;。斐波那契数列的定义如下&#xff1a; F(0) 0, F(1) 1 …...

【C#基础】C# 数据类型总结

序号系列文章0【C#基础】初识编程语言C#1【C#基础】C# 程序通用结构2【C#基础】C# 基础语法解析文章目录前言数据类型一. 值类型&#xff08;Value types&#xff09;二. 引用类型&#xff08;Reference types&#xff09;三. 指针类型&#xff08;Pointer types&#xff09;结…...

再创荣誉 | Softing工业荣获CAIMRS 2023 数字化创新奖

在刚刚结束的中国工控-第二十一届“自动化及数字化”年度评选&#xff08;CAIMRS 2023&#xff09;中&#xff0c;Softing凭借edgeAggregator产品荣获“数字化创新奖”&#xff01; 经层层筛选&#xff0c;Softing edgeAggregator边缘聚合服务器从中脱颖而出&#xff0c;摘得C…...

Multi Paxos

basic paxos 是用于确定且只能确定一个值&#xff0c;“只确定一个值有什么用&#xff1f;这可解决不了我面临的问题,例如每个用户都要多次保存数据.” 你心中可能有这样的疑问。 原simple paxos论文里有提到一连串个instance of paxos [4] 但没有提出 multi paxos的概念&…...

Android - dimen适配

一、分辨率对应DPIDPI名称范围值分辨率名称屏幕分辨率density密度&#xff08;1dp显示多少px&#xff09;ldpi120QVGA240*3200.75&#xff08;120dpi/1600.75px&#xff09;mdpi160&#xff08;基线&#xff09;HVGA320*4801&#xff08;160dpi/1601px&#xff09;hdpi240WVGA4…...

深度学习网络模型——RepVGG网络详解

深度学习网络模型——RepVGG网络详解0 前言1 RepVGG Block详解2 结构重参数化2.1 融合Conv2d和BN2.2 Conv2dBN融合实验(Pytorch)2.3 将1x1卷积转换成3x3卷积2.4 将BN转换成3x3卷积2.5 多分支融合2.6 结构重参数化实验(Pytorch)3 模型配置论文名称&#xff1a; RepVGG: Making V…...

仓库拣货标签应用案例

使用场景&#xff1a;富士康成都仓库 解决问题&#xff1a;仓库亮灯拣选&#xff0c; 提高作业效率和物料明晰展示仓库亮灯拣选使用场景&#xff1a;京东仓库 解决问题&#xff1a;播种墙分拣&#xff0c;合单拣货完成后按订单播种播种墙分拣使用场景&#xff1a;和尔泰智能料…...

介绍一款HCIA、HCIP、HCIE的刷题软件

华为认证考试分为三个等级&#xff0c;分别为工程师HCIA、高级工程师HCIP、专家HCIE&#xff0c;等级越高&#xff0c;考试难度越大。 本篇带大家详细了解华为数通题库刷题工具的详细操作步骤。 操作须知&#xff1a;本款刷题工具为一款刷题小程序&#xff0c;无需安装即可在线…...

线程池整理汇总

它山之石&#xff0c;可以攻玉。借鉴整理线程池相关文章&#xff0c;以及自身实践。 文章目录1. 线程池概述2. 线程池UML架构3. Executors创建线程的4种方法3.1 newSingleThreadExecutor3.2 newFixedThreadPool3.3 newCachedThreadPool3.4 newScheduledThreadPool小结4. 线程池…...

华为OD机试真题Python实现【最短木板长度】真题+解题思路+代码(20222023)

🔥系列专栏 华为OD机试(Python)真题目录汇总华为OD机试(JAVA)真题目录汇总华为OD机试(C++)真题目录汇总华为OD机试(JavaScript)真题目录汇总文章目录 🔥系列专栏题目输入输出示例一输入输出说明示例二输入输出说明...

VMware安装CentOS7

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。个人爱好: 编程&#xff0c;打篮球&#xff0c;计算机知识个人名言&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准

城市路内停车管理常因行道树遮挡、高位设备盲区等问题&#xff0c;导致车牌识别率低、逃费率高&#xff0c;传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法&#xff0c;正成为破局关键。该设备安装于车位侧方0.5-0.7米高度&#xff0c;直接规避树枝遮…...

区块链技术概述

区块链技术是一种去中心化、分布式账本技术&#xff0c;通过密码学、共识机制和智能合约等核心组件&#xff0c;实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点&#xff1a;数据存储在网络中的多个节点&#xff08;计算机&#xff09;&#xff0c;而非…...

Springboot多数据源配置实践

Springboot多数据源配置实践 基本配置文件数据库配置Mapper包Model包Service包中业务代码Mapper XML文件在某些复杂的业务场景中,我们可能需要使用多个数据库来存储和管理不同类型的数据,而不是仅仅依赖于单一数据库。本技术文档将详细介绍如何在 Spring Boot 项目中进行多数…...