ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

vue 由 clearTimeout无法清除定时器引发的vue 周期函数,事件代码执行顺序思考

2022-01-31 09:58:56  阅读:232  来源: 互联网

标签:首页 定时器 console log clearTimeout vue 代码执行 timeOut 页面


vue 由 clearTimeout无法清除定时器引发的vue 周期函数,事件代码执行顺序思考

最近做个移动的项目,遇到需求:首页无操作20秒,自动退出登录。其他页面20秒无操作,自动跳转首页。

所谓的无操作,包括点击,触摸,滑动等用户行为。
这需求其实也很简单,思路就是使用定时器setTimeout设定时间,监听页面是否有点击,触摸,滑动等事件在操作,如果没有,则时间一到,就跳转首页或者退出登录,如果有事件发生,则清除定时器,然后重启定时器

那我们先来实现下这个逻辑,先放首页试试

<template>
  <div class="home" @click="screenClick" @touchmove="touchmove" @touchstart="touchStart" @touchend="touchEnd">
    <div class="home-img-box"></div>
    <div class="login-box row-center">
      <strong class="login-text">轻触屏幕,继续操作</strong>
    </div>
  </div>
</template>
<script>
export default {
  created() {
    this.screenClick()
  },
  methods:{
    /**
     * 屏幕在点击
     */
    screenClick(){
      // console.log('屏幕点击')
      this.delayUserHandle()
    },
    /**
     * 延迟
     */
    delayUserHandle(){
      window.clearTimeout(this.timeOut)
      // console.log('开始延迟')
      // console.log(this.timeOut)
      this.timeOut = window.setTimeout(()=> {
        // console.log('延迟结束')
        const {name} = this.$route
         if(name==='Home'){
            // 首页,
            this.$store.dispatch('logout')
          }else{
            this.$store.dispatch('logout')
            this.$router.replace('/')
            }
      },20000)
    },
    /**
     * 触摸开始
     */
    touchStart(){
      window.clearTimeout(this.timeOut)
    },
    /**
     * 触摸滑动
     */
    touchmove(){
      window.clearTimeout(this.timeOut)
    },
    /**
     * 触摸结束
     */
    touchEnd(e){
      // console.log('touchEnd')
      // console.log(e)
      this.delayUserHandle()
    }
  },
}
</script>

ok,这个就已经实现了一个页面的20秒无操作退出。
但是我们需要的是任意页面,而不是一个,所以,这一块有很多公用的地方。所以我们可以将公共的部分抽出来,这里使用mixins 混入。
新建 clear-login-info.js文件,这里放在src下的mixins文件夹中,同时,我们得在页面离开,销毁后,将定时器销毁。可以销毁定时器的地方有beforeDestroy,destroyed,beforeRouteLeave。开始的时候,没考虑那么多,直接用beforeRouteLeave,就是页面离开前的路由守卫。
clear-login-info.js 代码如下:

//清除用户信息
import {mapState} from "vuex";

export default {
  data(){
    return{
      timeOut:null,//定时器
    }
  },
  computed:{
    ...mapState(['hasLogin'])
  },
  created() {
    this.timeOut = setTimeout(()=>{
      this.$store.dispatch('clearInfo')
    },30000)
    this.screenClick()
  },
  methods:{
    /**
     * 屏幕在点击
     */
    screenClick(){
      this.delayUserHandle()
    },
    /**
     * 延迟
     */
    delayUserHandle(){
      window.clearTimeout(this.timeOut)
      // console.log('开始延迟')
      // console.log(this.timeOut)
      this.timeOut = window.setTimeout(()=> {
        // console.log('延迟结束')
        const {name} = this.$route
      if(name==='Home'){
            // 首页,
            this.$store.dispatch('logout')
          }else{
           this.$store.dispatch('logout')
            this.$router.replace('/')
            }
      },20000)
    },
    /**
     * 触摸开始
     */
    touchStart(){
      clearTimeout(this.timeOut)
    },
    /**
     * 触摸滑动
     */
    touchmove(){
      clearTimeout(this.timeOut)
    },
    /**
     * 触摸结束
     */
    touchEnd(){
      this.delayUserHandle()
    }
  },
  beforeRouteLeave(to,from,next){
    clearTimeout(this.timeOut)
    next()
  }
}

这就完了吗?的确是达到效果了,但是,仅仅如此也就没有本文了。有Bug.
使用后发现,从首页跳到其他页面后,不管是否有操作,20秒后都会跳转到首页。而且没有使用该效果的页面也会跳转到首页。
这里有个需要注意的地方就是,定时器并不会在页面销毁后自动消除。需要手动清除定时器。但是这里已经在beforeRouteLeave里面写了。那么原因就只要一个,真正起作用的定时器并没有被清除!

前面说过页面离开前可以清除定时器的有三个地方,beforeDestroy,destroyed和beforeRouteLeave,那么如果是跳转下一页面前,定时器没有消除成功,那我们就尽量在最后的时机来触发试试。首先destroyed肯定在beforeDestroy之后触发,所以我们需要比较下destroyed和beforeRouteLeave到底谁最后触发。验证方式也很简单,直接console.log打印即可。
首先在app.vue弄个路由跳转,这里假设有两个页面 首页和关于

<template>
<div>
   <router-link to="/mkf">关于</router-link>
    <router-link to="/home">首页</router-link>
    <router-view></router-view>
</div>
</template>

然后我们在首页来检测打印

<!--Home-->
<template>
  <div>Home</div>
</template>
<script>
export default {
  destroyed() {
    console.log('页面销毁')
  },
  beforeRouteLeave(to,from,next){
    console.log('路由守卫beforeRouteLeave')
    next()
  }
}
</script>

运行项目,在首页点击 跳转到 "关于"页面,看看浏览器打印结果
在这里插入图片描述
结果是destroyed最后执行。好,那我们吧清除定时器放在destroyed里面,将clear-login-info.js的beforeRouteLeave替换为destroyed

  destroyed() {
    // console.log('销毁')
    window.clearTimeout(this.timeOut)
  },

继续测试,我们发现,定时器依然没有被清除。
因为destroyed执行的时候,页面其实已经切换到新页面了。这时候去清楚上页面的定时器,变量可能已经不存在,所以没有清除成功。

这个问题比较烦,就不再继续测试了。总之不能在destroyd清除定时器,这方案不得行,这样使用会发现,定时器经常没有被清除掉。

思考了一下,这个需求,使用定时器加vuex即可解决。

标签:首页,定时器,console,log,clearTimeout,vue,代码执行,timeOut,页面
来源: https://blog.csdn.net/qq_41000974/article/details/122137222

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有