vue + vue-router写登陆验证的同步方法和异步方法,及页面组件的分离和后端代码

先写一个用vue cdn写一个登陆验证的小示例+后端代码

前端719.html

<div id="app"><div id="loginForm">//路由层,登陆页和后台主页<router-link to="/">Login</router-link><router-link to="/home">Home</router-link></div>//展示组件的具体页<div><router-view></router-view></div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.13/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.4.2/vue-router.js"></script>
<script>const Login={template:`<div><h3>后台登陆</h3><form @submit="login">	//绑定login事件<div><label for="username">用户:</label><input type="text" id="username" v-model="username" required></div><div><label for="pwd">密码:</label><input type="password" id="pwd" v-model="pwd" required></div><button type="submit">登陆</button>            </form>    </div>`,data(){return{username:'',	//与上面的input进行双向绑定pwd:''}} ,methods:{//触发login事件login(){//获取到用户填写的用户名和密码let result={username:this.username,pwd:this.pwd}//连接后端APIfetch('http://localhost:3000/api/login',{method:'post',body:JSON.stringify(result),headers:{'content-type':"application/json"}}).then((response)=>{if(response.ok){return response.json(); //返回json数据}}).then(data=>{console.log(data);if(data.success){console.log('准备跳转到/home');//路由跳转到homethis.$router.push('/home');}else{alert('登陆失败:'+data.message);}}).catch(error=>{console.error('登陆错误:',error);})}}   };//组件homeconst Home={template:`<div><h3>Home page</h3><p>欢迎来到后台页面</p></div>`};//将组件添加路由中去const router=new VueRouter({mode:'hash',	//模式为#+组件页面routes:[{path:'/',component:Login},{path:'/home',component:Home,beforeEnter:validataUser}	//beforeEnter在进入页面前进行验证]});const app=new Vue({router}).$mount("#app");//验证函数function validataUser(to,from,next){fetch('http://localhost:3000/api/check-auth').then((response)=>{if(response.ok){return response.json();}}).then(data=>{console.log('验证结果:',data);if(data.isAthenticated){next();}else{next('/');}}).catch(error=>{console.log('验证错误:',error);next('/');});}
</script>

//后端代码用的nodejs的express写的login.js

const express=require('express');
const bodyParser=require('body-parser');
const cors=require('cors'); //允许跨域
const app=express();
const port=3000;app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.use(cors());//判断是否已经验证过
let isAthenticated=false;app.post('/api/login',(req,res)=>{const {username,pwd}=req.body;console.log(req.body)if(username==='admin'&& pwd==='123456'){isAthenticated=true;res.json({success:true});}else{res.json({success:false,message:'登陆失败'});}
});
//判断是否已经验证过的用户接口,主要用于后台主页判断
app.get('/api/check-auth',(req,res)=>{res.json({isAthenticated:isAthenticated});
});app.listen(port,()=>{console.log('服务器监听端口已经开启:',port);
});

这样你基本上就写了一个简单的登陆验证页面了。

下面写一个组件分离的代码

先写我们的主要路由和显示页面
App.vue
//这个很简单就是把router-link to路由到相关的页面即可,然后导出为App
//相当于分解上面719.html小示例

<template><div :class="$style.container"> <div><router-link to="/">登陆</router-link><router-link to="/home">后台</router-link></div><div><router-view></router-view></div>   </div>
</template><script>
export default{name:'App'
}
</script><style module>
.container {margin: 0;padding: 0;width: 100%;height: 100vh;background: url(/img/bg.webp) no-repeat center center;background-size: cover;position: relative;z-index: 0;
}</style>

//第2步写登陆页面
这里就是把登陆模板template、javascript代码、style写在一起
login.vue

<template><div :class="$style.loginDiv">  //绑定样式类loginDiv,这种是style为模块module可以这样写,如果style为scoped则直接写class="loginDiv"<h3>登陆</h3><form @submit.prevent="login" autocomplete="off">  //绑定login事件<div :class="$style.listDiv"><label for="username">&emsp;户:</label><input type="text" id="username" name="username" v-model="username" required autocomplete="false" @blur="validata" @input="validataOnInput"> //绑定blur、input事件,blur为失焦,input为输入事件<span v-if="error.username" :class="$style.errorMessage">{{error.username}}</span></div><div :class="$style.listDiv"><label for="pwd">&emsp;码:</label><input type="password" id="pwd" name="pwd" v-model="pwd" required autocomplate="false" @blur="validata" @input="validataOnInput"><span v-if="error.pwd" :class="$style.errorMessage">{{error.pwd}}</span></div><div :class="$style.listDiv"><button type="submit" :class="$style.btn">&emsp;</button></div></form></div>
</template>
<script>export default{data(){return{username:'',pwd:'',error:{username:'',pwd:''}}},methods:{login(){//只要验证未通过则return,表示不会进行下面的fetch接交给后端if(!this.validata()){return;}let result={username:this.username,pwd:this.pwd};fetch('http://localhost:3000/api/login',{method:'post',body:JSON.stringify(result),headers:{'content-type':"application/json"}}).then((response)=>{if(response.ok){return response.json();}}).then(data=>{console.log(data);if(data.success){console.log('准备跳转到/home');this.$router.push('/home');}else{alert('登陆失败:'+data.message);}}).catch(error=>{console.error('登陆错误:',error);})},//输入时就验证,有错误信息就进行validata验证直到无错误为止validataOnInput(){if(this.error.username || this.error.pwd){this.validata();}},validata(){let isValid = true;if (this.username.length < 5) {this.error.username = '用户名不能小于5个字符';isValid = false;} else {this.error.username = '';}if (this.pwd.length < 5) {this.error.pwd = '密码不能小于5个字符';isValid = false;} else {this.error.pwd = '';}return isValid;}},};
</script>
<style module>
div.loginDiv
{margin: 0 auto;width: 500px;height: 300px;border: 1px solid black;border-radius: 15px;background-color:azure;opacity: 0.7;position: relative;top: 230px;z-index: 9;box-shadow: 0 10px 10px rgba(0,0,0,0.5);
}
div.loginDiv form,label,input
{margin:10px;position: relative;z-index: 99;opacity: 1;
}
div.listDiv
{width: 100%;height: 60px;vertical-align: middle;}
div.loginDiv label
{font-size: 16px;
}
div.loginDiv input
{width: 250px;height: 35px;font-size: 16px;text-indent:5px;
}
.btn
{width: 200px;height: 40px;background-color: rgb(20, 134, 20);color: white;font-size: 16px;border:none;border-radius: 5px;margin-left: 100px;margin-top: 20px;
}
.errorMessage
{display: block;heigth:20px;font-size: 12px;color:red;
}
</style>

下面是home.vue
这个就非常的简单

<template><div class="homeDiv"><h3>后台主页</h3><p>welcome to the home page</p></div>
</template>
<script>
export default{name:'Home'
}
</script>

然后将三个组件合并到路由中
login2.js

import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './app.vue';
import Login from './components/Login.vue';
import Home from './components/Home.vue';Vue.use(VueRouter);//将组件写入路由中
const routes=[{path:'/',name:'Login',component:Login},{path:'/home',name:"Home",component:Home,	//这里的beforeEnter验证接口为api/check-auth,就是判断是否已经验证过的用户beforeEnter(to,from,next){fetch('http://localhost:3000/api/check-auth').then((response)=>{if(response.ok){return response.json();}}).then(data=>{console.log('验证结果:',data);if(data.isAthenticated){next();}else{next('/');}}).catch(error=>{console.log('验证错误:',error);next('/');});}}
];const router=new VueRouter({routes:routes
});
new Vue({el:"#app",router,render:h=>h(App)
})

//访问的主入口代码login2.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>Vue Router example</title></head>
<body><div id="app"></div><script  type="module" src="./login2.js"></script>
</body>
</html>

现在你进入cmd并进入到你代码的根目录中用 node login.js 运行后端代码
然后开启第2个cmd并进入到代码根目录,使用vite进行热测试 运行 npm run dev 进行预览
你会看以一个登陆页面如:
在这里插入图片描述
上面的login.vue中是一个同步登陆过程
现在我们把改成异步登陆过程

<template><div :class="$style.loginDiv"><form @submit.prevent="handleSubmit" autocomplete="off"><div :class="$style.listDiv"><label for="username">&emsp;:</label><inputtype="text"id="username"v-model="username"required@blur="validateField('username')" //失焦就验证@input="debouncedValidate"		//防抖,输入验证autocomplete="false"><span v-show="errors.username" :class="$style.errorMessage">{{errors.username }}</span>    </div><div :class="$style.listDiv"><label for="pwd">&emsp;:</label><inputtype="password"id="pwd"v-model="pwd"required@blur="validateField('pwd')"@input="debouncedValidate"autocomplete="false"><span v-show="errors.pwd" :class="$style.errorMessage">{{errors.pwd}}</span>    </div><div :class="$style.listDiv"><button type="submit" :class="$style.btn" :disabled="isSubmitting">{{isSubmitting ? '验证中...' : '登陆'}}</button></div></form></div>
</template>
<script>
import {debounce} from 'lodash-es'; //防抖模块
export default{data(){return{username:'',pwd:'',isSubmitting:false,	//防重复提交errors:{username:'',pwd:''}}},//生命周期钩子函数,在实例创建后被调用,但dom还未生成时作用于数据上created(){//防抖函数,延迟(300ms)this.debouncedValidate=debounce(this.validateAll,300);//监听自定义验证事件this.$on('form-validate',this.validateAll);},beforeDestroy(){//移除事件监听this.$off('form-validate',this.validateAll);//取消防抖this.debouncedValidate.cancel();},methods:{async handleSubmit(){this.$emit('form-validate');    //触发全局验证const isValid=await this.validateAll();if(!isValid)return;this.isSubmitting=true;try{const response=await fetch('http://localhost:3000/api/login',{method:'post',headers:{'Content-type':"application/json"},body:JSON.stringify({username:this.username,pwd:this.pwd})});const data=await response.json();if(data.success){this.$router.push('/home');}else{alert(`${data.message}`);}}catch(error){console.error('登陆错误:',error);alert('网络请求失败,请重试');}finally{this.isSubmitting=false;}},async validateField(field){return new Promise((resolve,reject)=>{//$nextTick在 DOM 更新完成后执行某些操作,这里就是输入数据后进行验证,每输入1次验证一次this.$nextTick(()=>{let isValid=true;if(field==='username'){isValid=this.username.length>=5;this.errors.username=isValid ? "" : '用户名不能小于5个字符';}else if(field==='pwd'){isValid=this.pwd.length>=6;this.errors.pwd=isValid ? "" : '密码不能小于6个字符';}resolve(isValid);});});},async validateAll(){//合成期约,都是true时返回一个[true,true]的resolve数组,如果一个为false,则中断返回那个中断的错误信息const results=await Promise.all([this.validateField('username'),this.validateField('pwd')]);return results.every(result=>result);}},
}
</script><style module>
div.loginDiv
{margin: 0 auto;width: 500px;height: 300px;border: 1px solid black;border-radius: 15px;background-color:azure;opacity: 0.7;position: relative;top: 230px;z-index: 9;box-shadow: 0 10px 10px rgba(0,0,0,0.5);
}
div.loginDiv form,label,input
{margin:10px;margin-top:25px;position: relative;z-index: 99;opacity: 1;
}div.listDiv
{width: 100%;height: 60px;vertical-align: middle;margin-top: 15px;
}
div.listDiv span
{text-align: left;text-indent: 100px;width: 100%;
}
div.loginDiv label
{font-size: 16px;
}
div.loginDiv input
{width: 250px;height: 35px;font-size: 16px;text-indent:5px;
}
.btn
{width: 200px;height: 40px;background-color: rgb(20, 134, 20);color: white;font-size: 16px;border:none;border-radius: 5px;margin-left: 100px;margin-top: 20px;
}
.errorMessage
{display:block;font-size:12px;height:20px;    /*固定高度防止布局抖动*/color:red;
}
.btn:disabled{opacity:0.7;cursor:not-allowed;
}
</style>

现在把login2.js中的改成import Login from ‘./components/Login2.vue’;
就可以使用异步验证方法了

最后用vite来进行打包

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/87104.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/87104.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.netcore 一个mvc到静态html实现

一、新建Mvc项目 Program.cs添加拦截 二、添加一个集成测试 将页面转为html到wwwroot下面 UnitGenHtml.cs using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.VisualStudio.TestPlatform.TestHost;namespace SaaS.OfficialWeb…

实现Taro小程序+nut-ui左滑删除效果

Taro小程序开发中&#xff0c;使用nut-ui组件&#xff0c;实现左滑删除卡片效果&#xff08;自定义删除按钮样式&#xff09; html代码部分 <nut-swipe class"carBox" v-for"(item, index) in carList" :key"item" :ref"(el) > se…

LLM 系列(五):模型训练篇

一个面向 Java 开发者的 Sring-Ai 示例工程项目&#xff0c;该项目是一个 Spring AI 快速入门的样例工程项目&#xff0c;旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计&#xff0c;每个模块都专注于特定的功能领域&#xff0c;便于学习和…

Oracle LogMiner分析日志的三种方法示例

Oracle LogMiner分析日志的三种方法示例 方法一:Online Catalog作为日志挖掘字典自动获取日志模式手动获取日志模式方法二:Redo Log作为日志挖掘字典自动获取日志模式手动获取日志模式方法三:Flat File作为日志挖掘字典自动获取日志模式手动获取日志模式📖 Oracle LogMine…

Java 中 List.stream() 的全面使用指南(含完整示例)

标签&#xff1a;Java8, Stream API, 函数式编程, 集合操作 一、前言 随着 Java 8 的推出&#xff0c;Stream API 成为了处理集合数据的一种高效方式。List.stream() 是 Java Stream API 的入口方法之一&#xff0c;它允许开发者将集合转换为流&#xff0c;并通过链式调用实现…

香港 8C 站群服务器买来可以做哪些业务?

香港8C站群服务器&#xff08;即提供8个不同C段IP地址的服务器&#xff09;凭借多IP独立分配、低延迟网络及免备案优势&#xff0c;适用于以下关键业务场景&#xff1a; 一、SEO优化与搜索引擎运营 SEO站群搭建&#xff1a;为 80-100 个网站分配 8 个不同 C 段 IP &#xff0…

UI前端与数字孪生融合新趋势:智慧医疗的可视化诊断辅助

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩! 一、引言&#xff1a;数字孪生重塑智慧医疗诊断范式 在医疗数字化转型的浪潮中&#xff0c;数…

OpenBayes 一周速览丨Nanonets-OCR-s深度语义理解,精准结构化转换;HLE人类问题推理基准上线,含2.5k题目,助力封闭式评估体系构建

公共资源速递 5 个公共数据集&#xff1a; * Brain Tumor 脑肿瘤数据集 * HLE 人类问题推理基准数据集 * OpenThoughts3-1.2M 推理数据集 * Nemotron-Personas 人物角色数据集 * OpenMathReasoning 数学推理数据集 14 个公共教程&#xff1a; 音频生成 * 2 视频生成 *…

ABB CH-3185 3 bhl 000986 p 1006 ab ability 800 xa自动化系统

安全性总结(续) 操作环境 在AC 800M控制器系统上线之前&#xff0c;调查哪些环境条件适用。请特别注意以下几点: 控制器不得暴露在超过相关技术规范中给定值的条件下。 控制器不得在暴露于强电气干扰的环境中使用。电机可能产生超过设备允许水平的干扰&#xff0c;例如在维…

【算法】动态规划 斐波那契类型:1137. 第 N 个泰波那契数

1137. 第 N 个泰波那契数 简单 相关标签 premium lock icon 相关企业 提示 泰波那契序列 Tn 定义如下&#xff1a; T0 0, T1 1, T2 1, 且在 n > 0 的条件下 Tn3 Tn Tn1 Tn2 给你整数 n&#xff0c;请返回第 n 个泰波那契数 Tn 的值。 示例 1&#xff1a; 输入&am…

图像编辑新变革 !ComfyUI-Kontext-fp8本地部署教程,120B参数对标闭源巨头

一、介绍 ComfyUI 是一个强大的、模块化的 Stable Diffusion 界面与后端项目。该用户界面将允许用户使用基于图形/节点/流程图的界面设计和执行高级稳定的扩散管道。 关于 FLUX.1 Kontext Dev FLUX.1 Kontext 是 Black Forest Labs 最新推出的突破性多模态图像编辑模型&#…

软件安装——下载安装ollama

一、下载&#xff08;模型管理工具&#xff09;&#xff1a; 下载地址&#xff1a;Ollama 二、自定义安装&#xff1a; 1.令行安装方式如下&#xff1a; 在OllamaSetup.exe所在目录打开cmd命令行&#xff0c;然后命令如下&#xff1a; OllamaSetup.exe /DIRE:\AllEdit\Ai…

springboot集成mqtt收发消息

在 Spring Boot 中使用 MQTT 可以通过集成 Eclipse Paho 或 HiveMQ 等客户端库实现。以下是完整的整合步骤&#xff0c;包括配置、发布和订阅消息的示例。 1. 添加 MQTT 依赖 在 pom.xml 中添加 Paho MQTT 客户端依赖&#xff1a; <dependency><groupId>org.spri…

Java 编程之备忘录模式

前言 有时候&#xff0c;我们真希望人生能有“CtrlZ”。在日常生活中&#xff0c;我们经常使用“撤销”功能&#xff0c;例如在写 Word、画图、写代码时一不小心操作失误&#xff0c;就希望能回到之前的状态。这种**“状态快照 恢复”**机制&#xff0c;在设计模式中就叫做&a…

yolov13+bytetrack的目标跟踪实现

目录 1. 介绍 2. 相关工作 (Related Works) 3. 方法 (Method) 4. 统计和结果 5. 技术实现 ByteTrack: Multi-Object Tracking by Associating Every Detection Box 1. Motivation 2. BYTE 3. ByteTrack 具体代码 UI界面设计 历史记录 完整代码实现UI界面 1. 介绍 …

GO类型转换与断言面试题及参考答案

Go 中类型转换与类型断言的区别是什么? 在Go语言里,类型转换和类型断言是两个不同的概念,它们在应用场景、语法格式以及底层实现上都存在明显差异。 类型转换主要用于将一种数据类型转变为另一种数据类型,一般适用于基本数据类型之间的转换,像整数与浮点数、字符串与字节…

【力扣 中等 C】79. 单词搜索

目录 题目 解法一&#xff1a;回溯 题目 解法一&#xff1a;回溯 void swap(char* a, char* b) {char tmp *a;*a *b;*b tmp; }void reverse(char* str) {int start 0, end strlen(str) - 1;while (start < end) {swap(&str[start], &str[end--]);} }bool se…

【数据标注师】分类标注

目录 一、 **分类标注的认知底层逻辑**1. **三大核心挑战2. **四维评估标准** 二、 **五阶成长体系**▶ **阶段1&#xff1a;分类体系深度内化&#xff08;2-4周&#xff09;**▶ **阶段2&#xff1a;标注决策流程固化**▶ **阶段3&#xff1a;场景化标注策略**▶ **阶段4&…

大数据时代UI前端的智能化转型策略:以用户为中心的设计思维

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩! 一、引言&#xff1a;大数据驱动的 UI 前端变革浪潮 在数字化体验竞争白热化的今天&#xff…

【python实用小脚本-122】Detect Gender Webcam:基于Python和Keras的实时性别检测工具

在计算机视觉和人工智能领域&#xff0c;实时性别检测是一个具有广泛应用前景的技术。从安防监控到智能广告&#xff0c;性别检测可以帮助系统更好地理解和响应用户需求。为了实现这一功能&#xff0c;我们开发了一个基于Python和Keras的实时性别检测工具——detect_gender_web…