vue两种方式实现:用户长时间不操作退出到登录页
产品说,出于安全考虑,用户长时间不操作,就回到登录页面,让用户重新登录,就像银行的app一样。本文就记录一下实现这种效果的两种方式,分别是前端控制和后端控制,各有细节及适用使用场景前端控制(方式一)思路首先,用户长时间不操作具体表现形式是啥?其实就是事件是否长时间没有被触发执行。比如用户长时间不操作,就没有鼠标点击(click)事件、鼠标滚轮(mousewheel)事件、鼠标移动(mousemov
产品说,出于安全考虑,用户长时间不操作,就回到登录页面,让用户重新登录,就像银行的app一样。本文就记录一下实现这种效果的两种方式,分别是前端控制和后端控制,各有细节及适用使用场景
前端控制(方式一)
思路
首先,用户长时间不操作具体表现形式是啥?其实就是事件是否长时间没有被触发执行。
比如用户长时间不操作,就没有鼠标点击(click)事件、鼠标滚轮(mousewheel)事件、鼠标移动(mousemove)事件之类的,我们只需要监听这些事件,如果这些事件长时间没有触发,就说明用户长时间未操作,然后路由跳转到登录页面即可。
这三个事件我选择的是比较实用的鼠标点击事件,我们知道,一般来说项目的第一个页面是登录页面,所以在登录页面用户点击登录按钮的时候,就记录一下点击登录按钮的时间,存储到sessionstorage中去,当跳转到主页面的时候,当用户每点击一次页面,就更新一下sessionstorage中的存储的时间,同时也给页面绑定一个循环定时器,间隔一段时间就把当前时间和sessionstorage储存的上一次点击事件的时间做一个差值对比,当差值超过一定时间,就强制用户退出到登录页面即可。
代码
login.vue页面
// html <el-button type="primary" @click="loginIn">点击登录</el-button> // js methods: { loginIn() { // 存第一份点击的时间 sessionStorage.setItem("lastClickTime", new Date().getTime()); // 模拟后端返回存一个token sessionStorage.setItem('token',"token") this.$router.push({ path: "/", }); }, }
Home.vue页面
<template> <div class="homeBox"> <!-- 左边是菜单层级 --> <div class="left"> <div class="leftNav"> <el-menu :default-active="activeIndex" class="elMenu" background-color="#333" text-color="#B0B0B2" active-text-color="#fff" :unique-opened="true" router ref="elMenu" > <el-menu-item index="/vue"> <i class="el-icon-location-outline"></i> <span slot="title">vue页面</span> </el-menu-item> <el-menu-item index="/react"> <i class="el-icon-star-off"></i> <span slot="title">react页面</span> </el-menu-item> <el-menu-item index="/angular"> <i class="el-icon-pear"></i> <span slot="title">angular页面</span> </el-menu-item> </el-menu> </div> </div> <!-- 右边是视图层级 --> <div class="right"> <div class="rightTop"> <el-button type="primary" plain @click="loginOut">登出</el-button> </div> <div class="rightBottom"> <router-view></router-view> </div> </div> </div> </template> <script> export default { name: "Home", data() { return { activeIndex: this.$route.path, timer: null, }; }, created() { /* 第一步: 组件初始化加载就绑定监听点击事件,注意:addEventListener的第三个参数,这里要加上。 因为第三个参数决定了是冒泡还是捕获(false冒泡默认,true捕获),因为绑定监听点击事件,我们是在最 顶层的DOM位置进行捕获点击事件,所以第三个参数true,要加上的,这样的话,内层的任意地方的点击事件 我们就都能监听到了,然后存储一下点击的时间 */ window.addEventListener( "click", () => { // 为了方便,我们把点击事件的时间直接存到sessionStorage中去,这样方便获取比较 sessionStorage.setItem("lastClickTime", new Date().getTime()); }, true ); }, mounted() { /* 第二步: 组件初始化加载时也要绑定一个定时器,通过定时器定时轮询,去对比当前时间和上次点击的时间的差值 */ this.isTimeOut(); }, methods: { isTimeOut() { // 使用定时器之前,要清除一下定时器 clearInterval(this.timer); this.timer = setInterval(() => { let lastClickTime = sessionStorage.getItem("lastClickTime") * 1; // 把上次点击时候的字符串时间转换成数字时间 let nowTime = new Date().getTime(); // 获取当前时间 console.log("当前时间和之前点击时间", nowTime, lastClickTime); // 假设我们需求是:5秒钟不进行点击操作,就提示登录退出 if (nowTime - lastClickTime > 1000 * 5) { // 提示一下用户 this.$message({ type: "warning", message: "超时了,已退出登录" }); // 这里要清除定时器,结束任务 clearInterval(this.timer); // 最后返回到登录页 this.$router.push({ path: "/login" }); } }, 1000); }, }, beforeDestroy() { // 最后一步,离开页面的时候,清除一下定时器,也解绑点击事件 clearInterval(this.timer); window.removeEventListener("click", () => {}, true); }, }; </script>
这里注意一下,层级对应关系,我项目搭建的层级关系是Home.vue页面是App.vue页面的里面一层,也有对应的视图,视图对应的也是整个页面的关系。根据层级和路由表路由视图router-view关系,选择合适的层级去绑定对应的点击事件和定时器即可。
即层级关系是要选择和login.vue层级平行的下一级才行,否则就会在login.vue页面也会执行定时器和点击绑定事件了
效果图
后端控制(方式二)
思路
这种后端控制方式限制性没有前端控制强,但是也是可以用的。
我们知道用户长时间不操作就不会有发请求,这种方式我们和后端商定如下:
当用户这一次的请求和上一次请求的间隔时间超过一定时间,比如超过半小时。那么后端返回的状态码就不是200了,就是一个特殊的状态码,比如是4567这个状态码,那么我们在前端的响应拦截器中就可以加一个判断,如果状态码是4567就说明请求超时了,说明用户长时间未操作,这个时候直接路由跳转到登录页面即可
后端通过JWT机制去控制返回的状态码
代码
这里main.js中的Vue的实例对象我们将其挂载到全局对象window上,方便我们在响应拦截器中使用vm对象上的路由跳转方法
main.js文件
// 挂载到window对象上 window.vm = new Vue({ store, router, render: h => h(App), }).$mount('#app')
响应拦截器文件
http.interceptors.response.use((res) => { console.log('注册到全局上',vm); var code = res.data.code; if(code == 4567){ // 4567是超时状态码,看到这个标识我们就让用户退出登录 // 注意,这个时候路由跳转就不是this.$router.push()了 vm._router.push({ path: "/login" }); } return res.data }, (error) => { // console.log(error) return Promise.reject(error); })
打印vm实例对象
所以在响应拦截器中路由跳转变成了
vm._router.push({ path: "/login" })
了
总结
上述两种方式的思路都可以使用,具体使用哪种方式,视情况而定
更多推荐
所有评论(0)