下拉菜单功能的实现
下拉表单主要实现的是修改密码和退出系统功能。
一、修改密码功能的实现
需求是用户在输入原密码后,在输入框失去焦点后,系统对密码的正确性进行校验。并且用户在输入新密码和确认密码时进行二次校验。
1.1后台添加校验密码接口
校验密码是用来验证原密码的正确性。我们需要查找到用户密码和用户ID,由于要对数据进行处理,所以采用post方法。
router.js添加接口
//校验密码是否正确
router.post("/user/pwd",function (req,res) {
var body = req.body;
User.findOne({
//由于数据存储的时_id所以这里使用_id
_id:body.userId,
password:body.password
},function (err,data) {
if(err){
return res.status(500).json({
code: 3000,
flag: false,
message: "server error"
})
}
if(!data){
return res.status(200).json({
code: 4000,
flag: false,
message: "密码不正确"
})
}
return res.status(200).json({
"code": 2000,
"flag": true,
"message": "密码正确"
})
})
});
1.2后端添加修改密码接口
修改密码是查找用户ID,对查找到的用户data中的密码(password)进行修改。修改数据采用put。
//修改密码
router.put('/user/pwd',function (req,res) {
var id = req.body.userId;
console.log(req.body);
User.findOne({
_id:id
},function (err,data) {
if(err){
return res.status(500).json({
code: 3000,
flag: false,
message: "server error"
})
}
if(!data){
return res.status(200).json({
code: 4000,
flag: false,
message: "密码不正确"
})
}
data.password = req.body.password;
User.findByIdAndUpdate(id,data,function (err) {
if(err){
return res.status(500).json({
code: 3000,
flag: false,
message: "修改密码失败"
})
}
return res.status(200).json({
"code": 2000,
"flag": true,
"message": "修改密码成功"
})
})
})
});
1.3 前端api配置抵用接口
这里新建password.js文件用来发送前台请求和获取后台响应数据。
password.js
import request from "@/utils/request.js"
export default {
checkPwd(userId,password){
return request ({
url :"/user/pwd",
method: "post",
data:{
userId,
password
}
})
},
// 修改密码请求
updatePwd(userId,password){
return request({
url : "/user/pwd",
method:"put",
data:{
userId,
password
}
})
}
}
二、实现前端密码组件布局
2.1 前端AppHeader组件页面的实现
自定义校验规则
对话框弹出
这里使用了对话框弹出和自定义校验两个组件库。
<!-- 修改密码弹出框设置 -->
<el-dialog title="修改密码" :visible.sync="dialogFormVisible" width="500px">
<el-form
:model="ruleForm"
status-icon
:rules="rules"
ref="ruleForm"
label-width="100px"
style="width: 400px"
>
<el-form-item label="原密码" prop="oldPass">
<el-input type="password" v-model="ruleForm.oldPass"></el-input>
</el-form-item>
<el-form-item label="新密码" prop="pass">
<el-input type="password" v-model="ruleForm.pass"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input type="password" v-model="ruleForm.checkPass"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')"
>提交</el-button
>
<el-button @click="$refs['ruleForm'].resetFields()">重置</el-button>
</el-form-item>
</el-form>
</el-dialog>
2.1 密码校验和修改功能的实现
将我们新传入的数据在data函数中定义,然后定义方法。
在script中导入方法
import passwordApi from "@/api/password.js";
data中初始化数据,自定义规则
data() {
const validateOldPass = (rule, value, callback) => {
passwordApi.checkPwd(this.user.id, value).then((response) => {
const resp = response.data;
if (resp.flag) {
callback();
} else {
callback(new Error(resp.message));
}
});
};
const validatePass = (rule, value, callback) => {
if (value != this.ruleForm.pass) {
callback(new Error("两次输入密码不一致!"));
} else {
callback();
}
};
return {
user: JSON.parse(localStorage.getItem("msm-user")),
dialogFormVisible: false,
ruleForm: {
oldPass: "",
pass: "",
checkPass: "",
},
rules: {
oldPass: [
{ required: true, message: "旧密码不能为空", trigger: "blur" },
{ validator: validateOldPass, trigger: "blur" },
],
pass: [{ required: true, message: "新密码不能为空", trigger: "blur" }],
checkPass: [
{ required: true, message: "确认密码不能为空", trigger: "blur" },
{ validator: validatePass, trigger: "change" },
],
},
};
},
定义方法,打开弹出框实现密码的修改
methods: {
handleCommand(command) {
switch (command) {
case "a":
// 打开修改密码窗口
this.handlePwd();
break;
case "b":
// 退出系统
break;
default:
break;
}
},
handlePwd() {
this.dialogFormVisible = true;
this.$nextTick(() => {
this.$refs["ruleForm"].resetFields();
});
},
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
passwordApi
.updatePwd(this.user.id, this.ruleForm.checkPass)
.then((response) => {
const resp = response.data;
this.$message({
message: resp.message,
type: resp.flag ? "success" : "warning",
});
if (resp.flag) {
this.handleLogout();
this.dialogFormVisible = false;
}
});
} else {
console.log("error submit!!");
return false;
}
});
},
},
三、实现退出系统的功能
3.1 后台配置退出登录接口
// 退出登录
router.post("/user/logout", function (req, res) {
var body = req.body;
User.findOne({
token: body.token
}, function (err, data) {
if (err) {
return res.status(500).json({
code: 3000,
flag: false,
message: '登录信息存在错误'
})
}
if (!data) {
return res.status(200).json({
code: 4000,
flag: false,
message: '不存在'
})
}
return res.status(200).json({
code: 2000,
flag: true,
message: '退出登录成功'
})
})
})
3.2 前端api调用接口
这里的接口写在login.js文件下
// 用户退出登录
export function logout(token){
return request ({
method:"post",
url:'/user/logout',
data:{
token
}
})
}
3.2 AppHeader实现功能
这里我们要将admin动态绑定成用户昵称,所以将admin转换成 {{ user.nickname }}
<!-- 头部右部用户标签设置 -->
<el-dropdown @command="handleCommand">
<span class="el-dropdown-link">
{{ user.nickname }}<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="a">修改密码</el-dropdown-item>
<el-dropdown-item command="b">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
退出功能的实现
在script中导入方法
import { logout } from "@/api/login.js";
handleCommand(command) {
switch (command) {
case "a":
// 打开修改密码窗口
this.handlePwd();
break;
case "b":
// 退出系统
this.handleLogout();
break;
default:
break;
}
},
handleLogout() {
logout(localStorage.getItem("msm-token")).then((response) => {
const resp = response.data;
if (resp.flag) {
localStorage.removeItem("msm-token");
localStorage.removeItem("msm-user");
this.$router.push("/login");
} else {
this.$message({
message: resp.message,
type: "warning",
});
}
});
},
},
四、全局权限校验
原因:当用户未登录时,用户不能够进入项目主体页面,当出现该情况时,用户应被退出项目到登录页,如果用户未登录就回到注册页面,完成注册–>登录–>项目主页。
在msm项目文件夹下新建permission.js文件
permission.js
import router from './router' //导入路由
import {getUserInfo} from '@/api/login.js' //获取用户信息,判断项目是否含有用户信息
//通过router路由前置钩子函数 beforeEach() ,在跳转路由前进行拦截判断是否已经登录,如果已登录,则进行路由跳转,如果没有则回到登录页。
router.beforeEach((to, from, next) => {
//用户登录以后创建出的token,通过token来判断用户信息是否存在
const token = localStorage.getItem('msm-token')
//用户登录信息不存在,没有产生token
if (!token) {
//让用户前往登录页面,如果在登录页面继续操作
if (to.path == '/login') {
next();
//没有登录信息就去注册页面,如果在注册页面,继续操作
} else if (to.path === "/register") {
next();
} else {
//如果当前页面都不处于上两个页面,默认去登陆页面
next({
path: '/login'
})
}
//如果有token
} else {
//当前所处页面为登录,继续操作
if (to.path === '/login') {
next();
//当前页面为注册,继续操作
} else if (to.path === "/register") {
next();
} else {
//如果页面为项目页面,获取用户信息。
const userInfo = localStorage.getItem('msm-user');
//如果有用户信息,继续操作
if (userInfo) {
next();
} else {
//调用方法,获取用户信息
getUserInfo(token).then((response) => {
const resp = response.data;
// console.log('prer', resp)
//如果resp响应为true,那么获取用户信息成功并存储
if (resp.flag) {
localStorage.setItem('msm-user', JSON.stringify(resp.data))
} else {
//如果失败,去登陆页面。
next({
path: '/login'
})
}
})
}
}
}
})
总结
本章主要实现的是头部组件右侧下拉菜单的实现,主要功能包括修改密码和退出系统的功能。最后在配置全局权限校验,防止用户在未登录的状态进入到项目主页中去。
router.js新增代码
// 退出登录
router.post("/user/logout", function (req, res) {
var body = req.body;
User.findOne({
token: body.token
}, function (err, data) {
if (err) {
return res.status(500).json({
code: 3000,
flag: false,
message: '登录信息存在错误'
})
}
if (!data) {
return res.status(200).json({
code: 4000,
flag: false,
message: '不存在'
})
}
return res.status(200).json({
code: 2000,
flag: true,
message: '退出登录成功'
})
})
})
//校验密码是否正确
router.post("/user/pwd",function (req,res) {
var body = req.body;
console.log('post',body);
User.findOne({
_id:body.userId,
password:body.password
},function (err,data) {
if(err){
return res.status(500).json({
code: 3000,
flag: false,
message: "server error"
})
}
if(!data){
return res.status(200).json({
code: 4000,
flag: false,
message: "密码不正确"
})
}
return res.json({
"code": 2000,
"flag": true,
"message": "密码正确"
})
})
});
//修改密码
router.put('/user/pwd',function (req,res) {
console.log('put',req.body);
var id = req.body.userId;
console.log(req.body);
User.findOne({
_id:id
},function (err,data) {
if(err){
return res.status(500).json({
code: 3000,
flag: false,
message: "server error"
})
}
if(!data){
return res.status(200).json({
code: 4000,
flag: false,
message: "密码不正确"
})
}
data.password = req.body.password;
User.findByIdAndUpdate(id,data,function (err) {
if(err){
return res.status(500).json({
code: 3000,
flag: false,
message: "修改密码失败"
})
}
return res.status(200).json({
"code": 2000,
"flag": true,
"message": "修改密码成功"
})
})
})
});
login.js
//用于发送ajax请求
import request from "@/utils/request.js";
// 注册
export function register(username,nickname,password){ //这里的参数都是形参
return request({
method:"post",
url:"/user/register",
data:{ //需要向后台传输的数据是req,后台又会响应回来一个数据是res
username,
nickname,
password
}
})
}
// 登录
export function login(username,password){
return request({
method:"post",
url:"/user/login",
data:{
username,
password
}
})
}
//获取用户信息
export function getUserInfo(token){
return request({
method:"get",
url:`/user/info?token=${token}`,
})
}
// 用户退出登录
export function logout(token){
return request ({
method:"post",
url:'/user/logout',
data:{
token
}
})
}
password.js
import request from "@/utils/request.js"
export default {
checkPwd(userId,password){
return request ({
url :"/user/pwd",
method: "post",
data:{
userId,
password
}
})
},
// 修改密码请求
updatePwd(userId,password){
return request({
url : "/user/pwd",
method:"put",
data:{
userId,
password
}
})
}
}
AppHeader下的index.vue
<template>
<div class="header">
<a href="#">
<img src="@/assets/logo.png" width="25px" class="logo" />
<span class="title">学堂</span>
</a>
<!-- 头部右部用户标签设置 -->
<el-dropdown @command="handleCommand">
<span class="el-dropdown-link">
{{ user.nickname }}<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="a">修改密码</el-dropdown-item>
<el-dropdown-item command="b">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- 修改密码弹出框设置 -->
<el-dialog title="修改密码" :visible.sync="dialogFormVisible" width="500px">
<el-form
:model="ruleForm"
status-icon
:rules="rules"
ref="ruleForm"
label-width="100px"
style="width: 400px"
>
<el-form-item label="原密码" prop="oldPass">
<el-input type="password" v-model="ruleForm.oldPass"></el-input>
</el-form-item>
<el-form-item label="新密码" prop="pass">
<el-input type="password" v-model="ruleForm.pass"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input type="password" v-model="ruleForm.checkPass"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')"
>提交</el-button
>
<el-button @click="$refs['ruleForm'].resetFields()">重置</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script>
import { logout } from "@/api/login.js";
import passwordApi from "@/api/password.js";
export default {
data() {
const validateOldPass = (rule, value, callback) => {
passwordApi.checkPwd(this.user.id, value).then((response) => {
const resp = response.data;
if (resp.flag) {
callback();
} else {
callback(new Error(resp.message));
}
});
};
const validatePass = (rule, value, callback) => {
if (value != this.ruleForm.pass) {
callback(new Error("两次输入密码不一致!"));
} else {
callback();
}
};
return {
user: JSON.parse(localStorage.getItem("msm-user")),
dialogFormVisible: false,
ruleForm: {
oldPass: "",
pass: "",
checkPass: "",
},
rules: {
oldPass: [
{ required: true, message: "旧密码不能为空", trigger: "blur" },
{ validator: validateOldPass, trigger: "blur" },
],
pass: [{ required: true, message: "新密码不能为空", trigger: "blur" }],
checkPass: [
{ required: true, message: "确认密码不能为空", trigger: "blur" },
{ validator: validatePass, trigger: "change" },
],
},
};
},
components: {},
methods: {
handleCommand(command) {
switch (command) {
case "a":
// 打开修改密码窗口
this.handlePwd();
break;
case "b":
// 退出系统
this.handleLogout();
break;
default:
break;
}
},
handlePwd() {
this.dialogFormVisible = true;
this.$nextTick(() => {
this.$refs["ruleForm"].resetFields();
});
},
handleLogout() {
logout(localStorage.getItem("msm-token")).then((response) => {
const resp = response.data;
if (resp.flag) {
localStorage.removeItem("msm-token");
localStorage.removeItem("msm-user");
this.$router.push("/login");
} else {
this.$message({
message: resp.message,
type: "warning",
});
}
});
},
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
passwordApi
.updatePwd(this.user.id, this.ruleForm.checkPass)
.then((response) => {
const resp = response.data;
this.$message({
message: resp.message,
type: resp.flag ? "success" : "warning",
});
if (resp.flag) {
this.handleLogout();
this.dialogFormVisible = false;
}
});
} else {
console.log("error submit!!");
return false;
}
});
},
},
};
</script>
<style scoped>
.logo {
vertical-align: middle;
padding: 0 10px 0 40px;
}
.title {
color: white;
position: absolute;
}
.el-dropdown {
float: right;
margin-right: 40px;
}
.el-dropdown-link {
color: #409eff;
cursor: pointer;
}
.date-weather{
float: right;
color: white;
margin-right: 30px;
font-size: 12px;
}
</style>