Vue+Vuex 实现自动登录功能

刚刚实现了Vue+Vuex的自动登录功能,在实现的时候遇到了一些问题,这里记录一下:

因为这个还不够完善,在写完下列代码后,又进行了补充,可以从https://www.cnblogs.com/xiaoxineryi/p/12405563.html 看到补充内容

一、对于vuex的简单理解:

可以参考这个:https://zhuanlan.zhihu.com/p/24357762https://segmentfault.com/a/1190000009404727

还有官网文档:https://vuex.vuejs.org/zh/guide/getters.html

差不多理解就是,vuex里面,用state来存储数据,在mutations里面写保存数据的函数,并且提供给外部调用,在getters中写获取数据的函数,在actions里面写获取数据后、写入数据前的处理过程。

二、在看网上很多示例的时候,代码写得挺好的,但是没有总的项目目录,一个函数一个函数的写,却又不知道要放在哪里,就感觉很别扭,所以我先把项目目录列出来:因为只用到了src下的,其他的按新建项目的就好

            Vue+Vuex 实现自动登录功能

①:上一章的前后端分离里面,数据传递确实做到了,但是在Login.vue里面写的,很多重复的内容完全可以重用,所以这次干脆提出一个api来,专门用来传递数据。

  另外,此次使用的是aoxis,本身就已经封装好很多了。

import axios from 'axios'

let base = 'http://127.0.0.1:8090';
export const postRequest = (url, params) => {
return axios({
method: 'post',
url: `${base}${url}`,
data: params,
transformRequest: [function (data) {
// Do whatever you want to transform the data
let ret = ''
for (let it in data) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
}
return ret
}],
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
}

api.js

  base的路径,按照自己服务器的端口进行修改。

②:现在先在store里,定义好数据和方法(就相当于数据库):store/index.js

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex); const store = new Vuex.Store({ state: {
// 存储token
Authorization: localStorage.getItem('Authorization') ? localStorage.getItem('Authorization') : ''
}, mutations: {
// 修改token,并将token存入localStorage
changeLogin (state, user) {
// alert(user.Authorization);
state.Authorization = user.Authorization;
localStorage.setItem('Authorization', user.Authorization);
}
}
}); export default store;

  这里state里面就是存储的数据,这里就是存储用户的token,下面mutations,写了一个修改token的方法,这个方法将token写入localStorage,而且保存到自己的state中。

③:定义好了数据和方法以后,自动登录就是要在用户访问页面的时候,自动检查有没有token,token对不对:

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui'
import VueResource from 'vue-resource'
import 'element-ui/lib/theme-chalk/index.css'
// import './styles/element-variables.scss'
import './styles/font-awesome-4.7.0/css/font-awesome.min.css'
import './utils/filter_utils.js'
import store from './store'
import axios from 'axios' Vue.use(ElementUI)
// Vue.use(VueResource)
Vue.config.productionTip = false
// Vue.http.options.emulateJSON = true
/* eslint-disable no-new */ new Vue({
el: '#app',
router,
store:store,
components: { App },
template: '<App/>'
}) axios.interceptors.request.use(
config => {
if (localStorage.getItem('Authorization')) {
config.headers.Authorization = localStorage.getItem('Authorization');
}
return config;
},
error => {
return Promise.reject(error);
});

main.js

  在这里面,有两个需要注意的:

  第一个就是,因为定义了store,所以在常规的main之外,还在Vue里面多加了一个store,否则的话,在使用的使用就相当于与没有注册,查找不到,经常有如下错误:

  Cannot read property 'commit' of undefined

  第二个就是下面的拦截器:因为只是对全局的访问都配置,所以直接就在全局中写了,而且前面是axios.interceptors.request.xx,前面的axios就表示了是全局的。

  如果要对某个方法来使用,应该先创建一个axios,然后假设这个变量名为xx,则使用xx.interceptors来执行,后面用request或者response来表示是请求数据还是响应数据。

  更详细的可以看https://www.jianshu.com/p/646ed4edf51f

④:在router/index.js中,也就是路由里面,也需要添加内容:

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import login from '@/components/login.vue'
import home from '@/components/home.vue'
import logo from '@/components/HelloWorld.vue'
Vue.use(Router); const router = new Router({
mode:'history',
routes:[
{
path:'/login',
name:'登录',
component:login,
},
{
path:'/',
name:'主页',
component:logo,
}
]
}); router.beforeEach((to,from,next)=>{
if(to.path ==='/login'){
next();
}else {
let token = localStorage.getItem('Authorization');
if(token ===null || token ===''){
next('/login');
}else {
// alert(localStorage.getItem("Authorization"));
next();
}
}
}); export default router;

  第一点就是将router加上mode:'history',这个也不知道为啥,反正我写的时候,没有这个就不管什么页面都跳转到首页,怎么调都不管用,加上这一句话就好了。

  第二个就是定义了一个beforeEach的函数,这个可以检测来的请求路径、去的请求路径,加上token检测,可以让用户如果没有登录就自动跳转到登录界面。

⑤:再写登录页面:

<template>
<el-form :rules="rules" class="login-container" label-position="left"
label-width="0px" v-loading="loading">
<h3 class="login_title">系统登录</h3>
<el-form-item prop="account">
<el-input type="text" v-model="loginForm.username" auto-complete="off" placeholder="账号"></el-input>
</el-form-item>
<el-form-item prop="checkPass">
<el-input type="password" v-model="loginForm.password" auto-complete="off" placeholder="密码"></el-input>
</el-form-item>
<el-checkbox class="login_remember" v-model="checked" label-position="left">记住密码</el-checkbox>
<el-form-item style="width: 100%">
<el-button type="primary" @click.native.prevent="submitClick" style="width: 100%">登录</el-button>
</el-form-item>
</el-form>
</template>
<script>
import {postRequest} from '../utils/api'
import {putRequest} from '../utils/api'
import { mapMutations } from 'vuex';
export default{
data(){
return {
rules: {
account: [{required: true, message: '请输入用户名', trigger: 'blur'}],
checkPass: [{required: true, message: '请输入密码', trigger: 'blur'}]
},
checked: true,
loginForm: {
username: '11',
password: '123'
},
loading: false
}
},
methods: {
...mapMutations(['changeLogin']),
submitClick: function () {
var _this = this;
this.loading = true;
postRequest('/login', {
username: this.loginForm.username,
password: this.loginForm.password
}).then(resp=> {
_this.loading = false;
if (resp.status == 200) {
//成功
var json = resp.data;
if (json.status == 'success') { _this.userToken = 123;
// localStorage.setItem('Authorization',_this.userToken);
_this.changeLogin({Authorization:_this.userToken});
_this.$router.replace({path: '/'});
} else {
_this.$alert('登录失败!', '失败!');
}
} else {
//失败
_this.$alert('登录失败!', '失败!');
}
}, resp=> {
_this.loading = false;
_this.$alert('找不到服务器⊙﹏⊙∥!', '失败!');
});
}
}
}
</script>
<style>
.login-container {
border-radius: 15px;
background-clip: padding-box;
margin: 180px auto;
width: 350px;
padding: 35px 35px 15px 35px;
background: #fff;
border: 1px solid #eaeaea;
box-shadow: 0 0 25px #cac6c6;
} .login_title {
margin: 0px auto 40px auto;
text-align: center;
color: #505458;
} .login_remember {
margin: 0px 0px 35px 0px;
text-align: left;
}
</style>

这里一定不要忘了引入函数

⑥在这里我们可以看到,返回的是json数据,对应后台可以:先创建一个Bean,用来专门返回响应内容:

package com.example.Bean;

public class RespBean {
private String status;
private String msg; public RespBean() {
} public RespBean(String status, String msg) { this.status = status;
this.msg = msg;
} public String getStatus() {
return status;
} public void setStatus(String status) {
this.status = status;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
}
}

  而在controller中,直接调用即可:

package com.example.Controller;

import com.example.Bean.RespBean;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; @RestController
public class TestController { @CrossOrigin(origins = "*")
@RequestMapping("/login")
public RespBean login(
@RequestParam(value = "username", required = false) String username,
@RequestParam(value = "password",required = false) String password,
Model model
){
System.out.println("用户名为"+username);
System.out.println("密码为"+password);
if (username.equals("11")){
return new RespBean("success","登录成功");
}else{
return new RespBean("fail","登录失败");
}
}
}
上一篇:webbrowser 静音(刷新、点击网页的声音)(包括flash静音)


下一篇:iOS开发 Xcode中的Info.plist字段含义