头图

一. 场景再现

  1. 前两天接到一个需求,要求实现类似于 B站 的那种,当我同时打开多个 Tab 标签的时候,如果我在某一个窗口退出了,那么其它窗口的登陆状态也需要同步退出。如下图,我同时打开了两个 tab

    image.png
  2. 当我点击其中一个窗口的退出时,你会发现另外一个窗口也神奇的同步退出了。

    11.gif
  3. 经过查阅相关资料,比较简单的方法有两种,一个是 window.postMessage,另外一个就是监听 localStorage 的变化,接下来我会分别演示这两种方案。

二. 搭建一下基础样式

  1. 注意:样式方面,在这里我使用的是 UnoCSS ,将样式內联在了标签里,如果你还不了解这种写法,你可以点击下方的文章学习。不过即使你之前从未了解过 UnoCSS ,也不会影响你下面的阅读,因为样式不是本文的重点,并不影响整体阅读。
    🫱手把手教你如何创建一个代码仓库
  2. 如果恰好你使用了 Unocss 那么你可以直接复制我下面的代码快速开始今天的知识。

    <script setup lang="ts">
    import { ref } from "vue";
    
    const isLogin = ref<boolean>(true);
    </script>
    
    <template>
      <div class="w-100vw h-100vh text-14px text-black">
    <div
          class="w-full h-full flex items-center justify-center flex flex-col gap-10px"
    >
          <span>{{ isLogin ? "已登陆" : "已注销" }}</span>
          <button class="mr-10px" @click="">打开新窗口</button>
      <button @click="">退出</button>
    </div>
      </div>
    </template>
    
  3. 如果你没有用到 Unocss,你也不用担心,因为我们的样式非常简单,页面只有三个元素。一个表示是否已经登陆的文案,然后剩下两个按钮,一个是打开新窗口的功能,一个是退出登陆的功能。

    image.png

三. window.postMessage

  1. 我们快速书写一个打开新窗口的函数。

    image.png
  2. 此时我们还需在当前页面挂载以后给 window 绑定一个事件来搭配 window.open 之后我们要做的事情。这里我们给 window 绑定了一个监听事件,事件的名称叫做 "message",回调函数中的参数 e 我们暂时不需要关系,我们继续往下进行代码书写。

    image.png

    可以看到我们的 window.open 正确的打开了一个新的 tab
    12.gif
  3. 接下来我们编写我们的退出按钮的函数。

    image.png

    首先很简单,它把我们的 isLogin 变量标记为 false,我们就可以通过观察 span 标签中的文案变化观察我们的状态。
    image.png
    另外一个重点,这里我们用到了 window.opener 这个属性,这个属性代表着它上一级的窗口。我们要向谁发生消息?上一级窗口对吧?调用 target?.postMessage 函数,这个函数第一个参数就是我们要发送的消息。我们就用 “退出” 字符串当作我们退出的信号吧。第二个参数是我们用 / 表示默认为当前的 origin 。届时上一级窗口的回调函数的事件对象就会收到我们的消息。
  4. 试验一下,可以很清楚的看到,我们第一个父窗口已经收到了来自子窗口的消息 “退出”,它是事件对象的 data属性的值。

    13.gif
    那么此时我们就可以判断,如果收到了退出的信号,那么我也跟着把 isLogin 变量的值改为 false,也实现退出的动作。

    image.png
  5. 测试一下效果:

    14.gif

四. 监听 localStorage

  1. 关于 storage 事件,这里面有一个误区,希望读者不要被误导,这个事件无法监听 sessionStorage 的变化。在 MDN 的中文文档中,并没有特别明显指出这一点。

    image.png

    而在英文文档中明确指出了这个十分关键的信息。

    image.png

    知道了这个关键点,就知道为什么我要写明要使用 localStorage 了。

    原文地址: MDN Storage Event

  2. 其实这个事件的用法和上面的 “message事件” 非常类似。第一步,你只需把我们给 window 绑定的事件替换为 "storage" 即可。
    image.png
  3. 然后修改我们的 logOut 函数。在执行的时候在 localStorage 里写入一个 isLoginfalse 的状态。(storage 只能写入字符串类型的值,所以需要 JSON 序列化一下,基础知识不过多赘述。)

    image.png
  4. 可以看到,我们第二个 tab 退出的时候,第一个 tab 已经监听到了 storage 的变化了。

    15.gif

    我们看一下这个事件对象身上的信息,这里面有两个属性是我们需要的。一个是 key,也就是发生变化的值,另外一个是 newValue 代表我们刚刚设置的值。

    image.png
  5. 知道了这些信息,我们就可以在事件的回调函数中做一些处理。

    image.png
  6. 测试一下:

    16.gif

五. 总结

实现方法其实还挺简单的,在实际工作中,我们项目的实现就是将 token 存放到 localStorage 里,通过监听 token 的存在来实现多 tab 的同时退出和同时登陆。

其实还有别的方法,比如同时开启一个 webSocket,让后端搭配同步向 tab 发消息等。


FFF方
453 声望12 粉丝