先寫一個用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">用 戶:</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">密 碼:</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">登 陸</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">用 戶:</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">密 碼:</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來進行打包