当前位置: 首页 > 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;山不辞石…...

力扣24.两两交换链表中的节点

文章目录力扣24.两两交换链表中的节点题目描述方法1&#xff1a;非递归方法2&#xff1a;递归力扣24.两两交换链表中的节点 题目描述 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&…...

AtCoder Regular Contest 137 题解(A~C)

A-Coprime Pair 思路 我们知道两个质数之间并不会相隔太远&#xff0c;于是我们直接用暴力就可以通过这题。 先从大到小枚举答案&#xff0c;并且枚举所有可能的起点&#xff0c;当枚举到的两个值满足条件输出并结束程序即可。 代码 #include <bits/stdc.h> using n…...

【C语言】预处理指令

C语言预处理指令一、什么是预处理指令二、预处理指令特点三、文件包含四、C标准库<stdio.h>一、什么是预处理指令 C语言的源文件&#xff08;.c文件&#xff09;需要经过编译生成可执行程序&#xff0c;编译操作会将源文件转换成目标文件&#xff0c;对于 VC、VS&#x…...

Java基础之多线程JUC全面学习笔记

目录初识多线程多线程的实现方式常见的成员方法线程安全的问题死锁生产者和消费者线程池自定义线程池初识多线程 什么是多线程? 线程 线程是操作系统能够进行运算调度的最小单位。线程被包含在进程之中&#xff0c;是进程中的实际运作单位。 简单理解:应用软件中互相独立&…...

13.CSS文本样式

文本样式 h1 {color: blue; }● 回顾上一节的内容&#xff0c;我们让h1标题的文字变成了蓝色&#xff0c;注意如果html中有多个h1标签&#xff0c;那我们这种写法所有的h1标签都会变成蓝色&#xff0c;除了颜色&#xff0c;本节我们将学习更多的CSS属性 文字大小font-size h…...

西恩科技更新招股书:IPO前大手笔分红“套现”, 赵志安为实控人

2月14日&#xff0c;上海西恩科技股份有限公司&#xff08;下称“西恩科技”&#xff09;更新了招股书&#xff08;申报稿&#xff09;。据贝多财经了解&#xff0c;西恩科技于2022年8月12日递交上市申请材料&#xff0c;准备在创业板上市&#xff0c;此次是西恩科技第二次更新…...

【CentOS】有关时间的设置

目录环境信息date语法信息查看时间设置时间设置日期tzselecttimedatectl语法显示当前及所有时区修改时区hwclock语法读取硬件时钟使用硬件时钟设置系统时间使用系统时间设置硬件时钟如何理解硬件时钟和系统时钟环境信息 CentOS 7 date 语法信息 date --help用法&#xff1a…...

OpenCV制作Mask图像掩码

一、掩膜&#xff08;mask&#xff09; 在有些图像处理的函数中有的参数里面会有mask参数&#xff0c;即此函数支持掩膜操作&#xff0c;首先何为掩膜以及有什么用&#xff0c;如下&#xff1a; 数字图像处理中的掩膜的概念是借鉴于PCB制版的过程&#xff0c;在半导体制造中&am…...

C++STL剖析(九)—— unordered_map和unordered_multimap的概念和使用

文章目录1. unordered_map的介绍和使用&#x1f351; unordered_map的构造&#x1f351; unordered_map的使用&#x1f345; insert&#x1f345; operator[ ]&#x1f345; find&#x1f345; erase&#x1f345; size&#x1f345; empty&#x1f345; clear&#x1f345; sw…...

Android无菜单键,如何触发onCreateOptionsMenu(Menu menu)

文章目录小结问题及解决无法触发onCreateOptionsMenu(Menu menu)修改配置文件解决使用一个按钮来触发其它办法参考小结 现在的Android有三个键&#xff1a; 任务键&#xff0c;Home键&#xff0c;返回键&#xff0c;也就是没有菜单键了&#xff0c;那么如何如何触发onCreateOp…...