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
英文地址,請注明出處:http://en.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…