vue多tab页面全部关闭后自动退出登录

业务场景:主项目是用vue写的单页面应用,但是有多开页面的需求,现在需要在用户关闭了所有的浏览器标签页面后,自动退出登录。

思路:因为是不同的tab页面,我只能用localStorage来通信,新打开一个标签页(页面初次装载时),我就往数组中加一个页面,在(页面关闭或刷新等)页面卸载时移除它。这样就只需要在页面装载时(load事件)判断当前是不是刷新页面就可以了,只要是其他来源就直接登出。

代码

import { MessageBox } from 'element-ui'
import store from '@/store'

const cache_key = 'currently_open_page'
const event_key = 'currently_open_page_change'

const eve = new CustomEvent(event_key, {
  detail: {
    eventName: event_key,
    list: [],
    operationType: 'clear',
  },
})

/**
 * 主方法,外部只要调用此方法就可以了
 */
function mount() {
  window.addEventListener('beforeunload', function () {
    const currentRoute = getCurrentPage()
    delPage(currentRoute)
  })

  window.addEventListener('load', function () {
    // 添加监听
    addPageListener()
    // 网页通过“重新加载”按钮或者location.reload()方法加载
    if (window.performance.navigation.type != 1) {
      // 如果页面不是刷新进来,不管是任何来源,都可以认为是新进入页面,此时应该就去登录页面
      if (!getCurrentOpenPageList().length) {
        // 将当前页面的 URL 设置为新的 URL(不包含任何参数)
        history.pushState(null, null, window.location.href)
        window.location.hash = ''
        store.dispatch('user/logout')
      }
    }

    // 添加新的页面
    const currentRoute = getCurrentPage()
    addPage(currentRoute)
  })
}

/**
 * 获取当前的页面(tab页面),目前就用时间值吧
 * @returns
 */
function getCurrentPage(reset = false) {
  if (!window._currentPage || reset) {
    window._currentPage = 'page_' + new Date().getTime()
  }
  return window._currentPage
}

/**
 * 获取当前已打开的页面列表
 * @returns
 */
function getCurrentOpenPageList() {
  const t = window.localStorage.getItem(cache_key)
  if (t) {
    return JSON.parse(t)
  } else {
    window.localStorage.setItem(cache_key, JSON.stringify([]))
    return []
  }
}

/**
 * 往缓存中新增页面
 */
function addPage(page) {
  const list = getCurrentOpenPageList()
  list.push(page)
  eve.detail.list = list
  eve.detail.operationType = 'add'
  window.dispatchEvent(eve)
}

/**
 * 往缓存中移除页面
 */
function delPage(page) {
  const list = getCurrentOpenPageList()
  const findIndex = list.indexOf(page)
  if (findIndex != -1) {
    list.splice(findIndex, 1)
  }
  eve.detail.list = list
  eve.detail.operationType = 'delete'
  window.dispatchEvent(eve)
}

/**
 * 清除所有的页面
 */
function clearAllPage() {
  eve.detail.list = []
  eve.detail.operationType = 'clear'
  window.dispatchEvent(eve)
}

/**
 * 此方法在登陆后使用,登录后重载,清空当前页面列表
 * 此方法出现的原因:在实际使用中发现,正常情况下,用户手动点击标签页的关闭、整个浏览器的关闭,都可以正确的移除页面,
 *                 但是如果用户在任务管理器结束了浏览器进程,或者用户未关闭浏览器,直接关机了,此时并不会触发页面的beforeunload事件。
 *                 导致getCurrentOpenPageList()的数量会因为这样的操作越来越用,使得在load事件中写的判断永远触发不到了
 */
function loginAfterReload() {
  // 清空了所有的页面
  clearAllPage()
  // 将当前页面加回去
  addPage(getCurrentPage(true))
}

/**
 * 检查页面是否存在
 */
function checkPageExist() {
  const currentPage = getCurrentPage()
  const list = getCurrentOpenPageList()
  const find = list.find((x) => x == currentPage)
  return find ? true : false
}

function addPageListener() {
  // 此监听只会触发本页面
  window.addEventListener(
    event_key,
    function (event) {
      // 将数据存储到本地
      window.localStorage.setItem(cache_key, JSON.stringify(event.detail.list))
    },
    false
  )

  // 通知其他的同源页面,内容发生了变化
  let timer = null
  let onlyOne = false
  window.addEventListener('storage', (event) => {
    // 仅触发当前事件
    if (event.key != cache_key) return
    // 只要触发一次就好了
    if (onlyOne) return

    clearTimeout(timer)
    timer = setTimeout(async () => {
      // 检查页面是否依然在页面数组中
      if (!checkPageExist()) {
        onlyOne = true
        MessageBox.confirm('页面过期失效', '提示', {
          cancelButtonText: '关闭',
          confirmButtonText: '刷新',
          showCancelButton: true,
          closeOnClickModal: false,
          closeOnPressEscape: false,
        })
          .then(() => {
            window.location.reload()
          })
          .catch(() => {
            window.close()
          })
      }
    }, 1000)
  })
}

export {
  mount, // 外部在main.js中调用即可,哪里都无所谓
  loginAfterReload, // 在登录后调用
}


  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值