登录页
1、为了方便起见,先将element-ui的使用改为全局引入的方式。修改main.js文件如下:
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
//这个是局部引入,前面的文章有讲过
// import '../plugins/element'
import 'font-awesome/css/font-awesome.min.css'
import axios from 'axios'
import router from './router/index'
Vue.config.productionTip = false
Vue.prototype.axios = axios
Vue.use(ElementUI)
new Vue({
router,
render: h => h(App),
}).$mount('#app')
2、写登陆页面:
2.1、components文件夹下新建Login.vue
2.2、从element-ui官网找需要的组件:+
2.3、修改代码(包括数据和表单绑定)整合后:
<template>
<div class="login">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>疫起健康后台管理系统</span>
</div>
<el-form
:model="loginForm"
ref="loginForm"
label-width="100px"
>
<el-form-item label="用户名" prop="username">
<el-input
v-model="loginForm.username"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
type="password"
v-model="loginForm.password"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('loginForm')"
>登录</el-button>
<el-button @click="resetForm('loginForm')">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
export default {
data() {
return{
loginForm:{
username:'',
password:''
}
}
},
};
</script>
<style lang="scss">
.login{
width: 100%;
height: 100%;
position:absolute;
background: #88b2dc;
.box-card{
width: 450px;
margin: 160px auto;
.el-card__header{
font-size: 34px;
}
.el-button{
width: 30%;
}
}
}
</style>
3、修改路由:启动项目(使用重定向)和输入http://localhost/login,进入的页面都是为登录页面
import Vue from 'vue'
import Router from 'vue-router'
//import Home from '../components/Home.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
// component: Home
redirect:'/login',
component: () => import('@/components/Login') //路由懒加载
//component: resolve => require(['@/components/Home'], resolve) //异步加载
},
{
path: '/login',
name:'Login',
component: () => import('@/components/Login') //路由懒加载
//component: resolve => require(['@/components/Home'], resolve) //异步加载
},
{
path: '/home',
// component: Home
component: () => import('@/components/Home') //路由懒加载
//component: resolve => require(['@/components/Home'], resolve) //异步加载
}
],
mode: 'history'
})
运行结果:
4、登录验证
4.1 简易版,适用于小项目和简单的验证规则,实现:将验证规则直接写在html中
<template>
<div class="login">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>疫起健康后台管理系统</span>
</div>
<el-form :model="loginForm" ref="loginForm" label-width="100px">
<el-form-item
label="用户名"
prop="username"
:rules="[
{ required: true, message: '请输入用户名', trigger: 'blur' },
{
min: 4,
max: 10,
message: '长度在4-10位字符之间',
trigger: 'blur',
},
]"
>
<el-input v-model="loginForm.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item
label="密码"
prop="password"
:rules="[
{ required: true, message: '请输入密码', trigger: 'blur' },
{
min: 6,
max: 12,
message: '长度在6-12位字符之间',
trigger: 'blur',
},
]"
>
<el-input
type="password"
v-model="loginForm.password"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="login('loginForm')"
>登录</el-button
>
<el-button @click="resetForm('loginForm')">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
当输入框失去焦点时,会自动进行表单校验
4.2登录验证进阶版
①在表单里绑定rules,直接在Login.vue页面的data中写校验规则,写法参考element-ui的form表单
<template>
<div class="login">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>疫起健康后台管理系统</span>
</div>
<el-form
:model="loginForm"
ref="loginForm"
label-width="100px"
:rules="rules"
>
<el-form-item label="用户名" prop="username">
<el-input v-model="loginForm.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
type="password"
v-model="loginForm.password"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="login('loginForm')">登录</el-button>
<el-button @click="resetForm('loginForm')">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
export default {
data() {
// rule 是校验规则,value是input用户输入的值,callback是回调函数 参考element-ui的api文档
const validateName = (rule, value, callback) => {
// 请输入4-10位昵称
let reg = /(^[a-zA-Z0-9]{4,10}$)/;
if (value === "") {
callback(new Error("请输入用户名"));
} else if (!reg.test(value)) {
callback(new Error("请输入4-10位用户名"));
} else {
callback();
}
};
const validatePass = (rule, value, callback) => {
// 6-12位密码需要包含大小写字母和数字以及特殊符号
let pass =
/^\S*(?=\S{6,12})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/;
if (value === "") {
callback(new Error("请输入密码"));
} else if (!pass.test(value)) {
callback(new Error("6-12位密码需要包含大小写字母和数字及特殊符号"));
} else {
callback();
}
};
return {
loginForm: {
username: "",
password: "",
},
rules: {
username: [{ validator: validateName, trigger: "blur" }],
password: [{ validator: validatePass, trigger: "blur" }],
},
};
},
methods: {
login(loginForm) {
this.$refs[loginForm].validate((valid) => {
if (valid) {
console.log(this.loginForm);
} else {
console.log(this.loginForm);
}
});
},
resetForm(loginForm) {
this.$refs[loginForm].resetFields();
},
},
};
</script>
<style lang="scss">
.login {
width: 100%;
height: 100%;
position: absolute;
background: #88b2dc;
.box-card {
width: 450px;
margin: 160px auto;
.el-card__header {
font-size: 34px;
}
.el-button {
width: 30%;
}
}
}
</style>
效果:
小技巧:使用写校验规则插件
使用:按下f1(我的笔记本需要按下Fn+f1)
②在表单里绑定rules,校验规则封装后,再在Login.vue页面导入校验规则(更推荐)
在src下新建utlis文件夹,新建validate.js文件,把Login.vue页面data中的校验规则过来,修改为如下:
// 用户名匹配
export function nameRule(rule, value, callback) {
// 请输入4-10位昵称
let reg = /(^[a-zA-Z0-9]{4,10}$)/;
if (value === "") {
callback(new Error("请输入用户名"));
} else if (!reg.test(value)) {
callback(new Error("请输入4-10位用户名"));
} else {
callback();
}
}
// 密码正则匹配
export function passRule(rule, value, callback) {
// 6-12位密码需要包含大小写字母和数字以及特殊符号
let pass = /^\S*(?=\S{6,12})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/;
if (value === "") {
callback(new Error("请输入密码"));
} else if (!pass.test(value)) {
callback(new Error("6-12位密码需要包含大小写字母和数字及特殊符号"));
} else {
callback();
}
}
在Login.vue页面修改为:
<template>
<div class="login">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>疫起健康后台管理系统</span>
</div>
<el-form
:model="loginForm"
ref="loginForm"
label-width="100px"
:rules="rules"
>
<el-form-item label="用户名" prop="username">
<el-input v-model="loginForm.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
type="password"
v-model="loginForm.password"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="login('loginForm')">登录</el-button>
<el-button @click="resetForm('loginForm')">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
import { nameRule, passRule } from '../utils/validate.js'
export default {
data() {
return {
loginForm: {
username: "",
password: "",
},
rules: {
username: [{ validator: nameRule, trigger: "blur" }],
password: [{ validator: passRule, trigger: "blur" }],
},
};
},
methods: {
login(loginForm) {
this.$refs[loginForm].validate((valid) => {
if (valid) {
console.log(this.loginForm);
this.axios
.post("http://1.116.64.64:5004/api2/login", this.loginForm)
.then((res) => {
console.log(res);
if (res.data.status === 200) {
localStorage.setItem("username", res.data.username);
this.$message({ message: res.data.message, type: "success" });
this.$router.push("/home");
}
})
.catch((err) => {
console.error(err);
});
} else {
console.log(this.loginForm);
}
});
},
resetForm(loginForm) {
this.$refs[loginForm].resetFields();
},
},
};
</script>
<style lang="scss">
.login {
width: 100%;
height: 100%;
position: absolute;
background: #88b2dc;
.box-card {
width: 450px;
margin: 160px auto;
.el-card__header {
font-size: 34px;
}
.el-button {
width: 30%;
}
}
}
</style>
效果:
5、登录页面连接后端
第一种
首先:使用mock准备模拟一下网络请求后端接口:
① 在vscode终端输入,ctrl+c结束正在运行的项目,再下载mock插件,输入
npm i @shymean/mock-server -g
② 插件安装完成后,然后在磁盘中随便一个地方新建一个文件夹,命名为 mock; 在mock文件里面新建一个mock.js空文件;
在终端进入mock文件夹,输入命令mock,启动本地mock服务器,默认端口为7654
mock>mock server listen at 7654
操作步骤如下图:
打开mock.js这个文件,自己写一些测试数据如下:
//登录接口
Mock.mock(/login/, {
code: 200,
data: {
access_token: "748_bef_246_test",
expires_in: 7200,
}
})
//用户信息
Mock.mock(/userInfo/, {
code: 200,
user: {
userName:'admin',
password:'123456',
role:'admim',
}
})
第二种
找一个自己或别人写好的后端接口,B站有很多,找一下直接用
封装token
在utils文件夹下新建setToken.js文件,内容如下:
export function setToken(tokenKey, token) {
return localStorage.setItem(tokenKey, token)
}
export function getToken(tokenKey) {
return localStorage.getItem(tokenKey)
}
export function removeToken(tokenKey) {
return localStorage.removeItem(tokenKey)
}
在Login.vue进行导入使用
<template>
<div class="login">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>疫起健康后台管理系统</span>
</div>
<el-form
:model="loginForm"
ref="loginForm"
label-width="100px"
:rules="rules"
>
<el-form-item label="用户名" prop="username">
<el-input v-model="loginForm.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
type="password"
v-model="loginForm.password"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="login('loginForm')">登录</el-button>
<el-button @click="resetForm('loginForm')">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
import { nameRule, passRule } from '../utils/validate.js'
import { setToken } from '@/utils/setToken.js'
export default {
data() {
return {
loginForm: {
username: "",
password: "",
},
rules: {
username: [{ validator: nameRule, trigger: "blur" }],
password: [{ validator: passRule, trigger: "blur" }],
},
};
},
methods: {
login(loginForm) {
this.$refs[loginForm].validate((valid) => {
if (valid) {
console.log(this.loginForm);
this.axios
.post("http://1.116.64.64:5004/api2/login", this.loginForm)
.then((res) => {
console.log(res);
if (res.data.status === 200) {
// localStorage.setItem("username", res.data.username);
setToken("username", res.data.username);
this.$message({ message: res.data.message, type: "success" });
this.$router.push("/home");
}
})
.catch((err) => {
console.error(err);
});
} else {
console.log(this.loginForm);
}
});
},
resetForm(loginForm) {
this.$refs[loginForm].resetFields();
},
},
};
</script>
<style lang="scss">
.login {
width: 100%;
height: 100%;
position: absolute;
background: #88b2dc;
.box-card {
width: 450px;
margin: 160px auto;
.el-card__header {
font-size: 34px;
}
.el-button {
width: 30%;
}
}
}
</style>
二次封装axios
设置项目代理,修改vue.config.js文件如下:
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
open: true,
host: 'localhost',
proxy: {
'api': {
target: 'http://1.116.64.64:5004/api2/',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
})
项目根目录下新建service.js文件,进行封装axios
import axios from 'axios'
import { getToken } from '@/utils/setToken.js'
import { Message } from 'element-ui'
const service = axios.create({
baseURL: '/api', // baseURL会自动加在请求地址上
timeout: 3000
})
// 添加请求拦截器
service.interceptors.request.use((config) => {
// 在请求之前做些什么(获取并设置token)
config.headers['token'] = getToken('token')
return config
}, (error) => {
return Promise.reject(error)
})
// 添加响应拦截器
service.interceptors.response.use((response) => {
// 对响应数据做些什么
let { status, message } = response.data
if(status !== 200) {
Message({message: message || 'error', type: 'warning'})
}
return response
}, (error) => {
return Promise.reject(error)
})
export default service
使用二次封装的axios,依旧采用全局导入的方式,修改main.js文件如下:
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
// import '../plugins/element'
import 'font-awesome/css/font-awesome.min.css'
// import axios from 'axios'
import service from '../service'
import router from './router/index'
//或者这样导入:会自动找到index文件
//import router from './router'
Vue.config.productionTip = false
// Vue.prototype.axios = axios
Vue.prototype.service = service
Vue.use(ElementUI)
new Vue({
router,
render: h => h(App),
}).$mount('#app')
修改Login.vue页面,注释掉引入的setToken文件
<template>
<div class="login">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>疫起健康后台管理系统</span>
</div>
<el-form
:model="loginForm"
ref="loginForm"
label-width="100px"
:rules="rules"
>
<el-form-item label="用户名" prop="username">
<el-input v-model="loginForm.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
type="password"
v-model="loginForm.password"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="login('loginForm')">登录</el-button>
<el-button @click="resetForm('loginForm')">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
import { nameRule, passRule } from '../utils/validate.js'
// import { setToken } from '@/utils/setToken.js'
export default {
data() {
return {
loginForm: {
username: "",
password: "",
},
rules: {
username: [{ validator: nameRule, trigger: "blur" }],
password: [{ validator: passRule, trigger: "blur" }],
},
};
},
methods: {
login(loginForm) {
this.$refs[loginForm].validate((valid) => {
if (valid) {
console.log(this.loginForm);
this.service('/login',this.loginForm)
} else {
console.log(this.loginForm);
}
});
},
resetForm(loginForm) {
this.$refs[loginForm].resetFields();
},
},
};
</script>
<style lang="scss">
.login {
width: 100%;
height: 100%;
position: absolute;
background: #88b2dc;
.box-card {
width: 450px;
margin: 160px auto;
.el-card__header {
font-size: 34px;
}
.el-button {
width: 30%;
}
}
}
</style>
ctrl+c关掉当前运行的项目,重新新建终端输入:npm run serve,修改了vue.config.js文件一定要重启项目,配置才会生效,再进行接口测试,否则会报错如下:访问的依旧是localhhost:8080端口