论多窗口相互关联下window.open打开已在的窗口时只激活不刷新的实现方案

这篇具有很好参考价值的文章主要介绍了论多窗口相互关联下window.open打开已在的窗口时只激活不刷新的实现方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言~博主看到后会去代替大家踩坑的~
主页: oliver尹的主页
格言: 跌倒了爬起来就好~
来个关注吧,点个赞吧,谢谢

一、前言

近期,我司有个小伙伴遇到这么个场景实现起来感觉有点困难与我讨论,大概是这样的:
项目框架使用的是Vue开发的单页应用,这个单页应用在打开某个大模块路由时 需要使用window.open()去打开新的模块,也就是说如果打开的是大模块,那么会新建一个窗口,在这个窗口中打开页面,但是如果打开的换菜单又是小路由,那么使用的VueRouter切换路由,这就导致了一个问题,在重复点击大模块时出现了重复打开新窗口,并且后续又陆陆续续出现了许许多多的问题…因此有了本文作记录,以备后续不时之需~
耐心看完,也许你会有所收获~

二、本文内容概述

本文主要解决的场景是:
在类似Vue的单页应用项目中,在任意一个窗口内首次打开指定页面时通过新建窗口的方式打开,在任意一个窗口内打开已打开的界面时,仅激活对应窗口,比如:在A页面使用类似 window.open() 的效果打开了同域下的B页面和C页面(A,B,C页面具有相同的路由系统),切换窗口至B页面,点击B页面下的C页面地址,此时不会再次新建C页面窗口,而是将已打开的C页面窗口激活至可视状态,且C页面窗口不触发刷新保留原来的内容与操作状态;
同时,在任意界面中执行浏览器的f5刷新,不影响使用效果;
window.open打开新窗口不改变原窗口,高级前端工程之路,一些踩过的坑得留档,前端,javascript,vue.js,window.open,js打开窗口
先简单说一下实现思路吧,在openUrl的内部判断当前名为title的窗口是否打开过,如果没有打开过,执行 window.open() 方法新建窗口,如果打开过,执行 window.open('javascript:;', title) 去激活名为title的窗口,让它显示出来
如果有小伙伴想要文件,请直接跳转至 第五部分下载文件 即可~

三、待解决问题

为了完成上面的场景需求,实际开发中遇到的主要问题一共存在三个:

  1. 刷新的问题,当使用 window.open(url,name) 打开对应name的窗口时,如果该name的窗口已存在确实会仅仅是激活对应name的窗口,但是这个激活会执行刷新,它刷新这个网页,假如这个网页存在复杂表单,用户输入的一半的内容或者页面操作的状态都将会被刷新掉,据产品经理讲体验甚是不好…
  2. 多页面相互激活的问题,这个问题就比较有意思了,由于是Vue开发的单页应用,整个路由系统其实是同一套,这就会出现一个问题,在A页面通过 window.open() 打开了B页面和C页面,而B页面和C页面自身其实也包含完整的路由系统的,这个路由系统中自然也有A,B,C的路由地址,那如果在B页面通过 window.open() 打开C页面,此时正确的逻辑应该是仅仅去激活C页面的窗口,而不是重新再打开一个,示例图如下:
    window.open打开新窗口不改变原窗口,高级前端工程之路,一些踩过的坑得留档,前端,javascript,vue.js,window.open,js打开窗口

是不是挺有意思,这里面大概率存在通信问题,比如在C页面怎么知道在A页面中打开过哪些窗口并且获得窗口name等等~

  1. 缓存的问题,即浏览器刷新,在A页面执行浏览器的的f5刷新后,可以在点击对应模块时依然仅仅是去激活对应的模块页面,

四、问题解决说明

关于 window.open() 具体参数以及各个参数的说明可以看MDN的官方解释,具体链接如下:window.open

4.1 刷新问题解决

先说核心实现吧,刷新的问题核心解决应该是在激活的实现,而不是重新通过 window.open() 去打开url,经过实验,确认通过以下这个实现

window.open('javascript:;', name)

可能会有小伙伴奇怪,论激活窗口的功能不应该是通过 window.focus() 去实现么,使用 window.focus() 确实可以将指定name值的窗口激活,实现如下:

let win = null;
if(win){
  win.focus()
}
else{
  win = window.open(url, name);
}

但是由于我们的场景比较奇葩,需要实现跨窗口激活,也就是说在C页面打开B页面时需要在C页面执行B页面这个 win.focus(),但由于win这个对象它其实是一个最顶层的 window对象,它无法被传递,被转化,即想使用postMessage发送,会提示发送失败,根本无法跨窗口,同理,win也无法被缓存,一旦刷新界面,这个win对象就会丢失无法留存,自然待解决问题中第三个问题也同样无法实现;
在尝试 window.focus() 这条路走不通后,发现了另外一种方法,即上面说到的 window.open('javascript:;', name) 这个方法,这个方法同样可以解决激活窗口的问题,并且这个name值的类型是一个字符串,是窗口的名字也是 winodw.open() 中的name,代码如下

window.open(url, name);

这种方法的实现和focus()的实现非常接近,无非就是将 win.focus() 改成了 window.open('javascript:;', name)

if(判断是否打开过){
  window.open('javascript:;', name)
}
else{
 window.open(url, name);
}

4.2 多窗口的相互关联激活

多窗口的相互关联激活细想一下,上面采用的是 window.open('javascript:;', name) 实现的激活,在这个代码中唯一的变量就是一个字符串格式的name,扩展一下思维,在任意一个窗口里知道了其它窗口的name,是不是都可以通过 window.open('javascript:;', name) 实现激活,想了想从理论上来说这个方法应该是可行的(当然事实证明确实可以),剩下的就是要解决以下这三个小问题:

  1. 知道已打开窗口的name值,目的是为了方便使用 window.open('javascript:;', name) 去激活;
  2. 判断窗口是否已经打开过,目的是为了方便知道使用 window.open('javascript:;', name) 去激活窗口还是使用 window.open(url, name) 去打开窗口;
  3. 给每一个打开的窗口命名,这个name值是必须唯一的,并且需要和执行window.open('javascript:;', name) 中的name对应起来,不对应起来的话执行open的时候会找不到name值的窗口,自然也就无法实现激活;

4.2.1 确认窗口name值

name值的小问题其实非常好解决,这是一个Vue单页应用,路由名称和路由地址是固定的,也就是说,所有个这些个新窗口的路由也完全相同,而我们的路由往往是由菜单名字和路由地址组成的,具有唯一性(你总不能两个菜单的名字完全一模一样吧),因此往往是如下这种结构

// template
<div v-for="item in menuList" :key="item.value" @click="changeRouter(item)">
  <div>{{item.title}}</div>  
</div>

// js
changeRouter(item){
  window.open('javascript:;', item.title)
}

因此,到这里基本解决了一个小问题,多窗口由于共享的是一个路由系统,name的名字其实在各个页面是相互知道的,我们只需要知道这个name的窗口是否处于打开状态即可;

4.2.2 确认窗口是否已经打开过

如何确认窗口是否已经打开过?想了下,由于多个窗口实际上处于同域下,localStorage自然成了首选,当打开一个新页面时,往localStorage里插入一条消息,关闭页面的时候再到localStorage中将对应的窗口信息删掉;
大致的代码如下:
首先是存储信息

// 执行首次跳转
window.open(url, name)
// 将跳转的名字和地址保存下来
setTsLocalData(name, url)

function setLocalData(key, value) {
  let local = localStorage.getItem("demo")

  if (local) {
    local = JSON.parse(local)
  }

  console.log(local)
  const item = { ...local }
  item[key] = value

  localStorage.setItem("demo", JSON.stringify(item))
}

接着在执行跳转前加一个判断,判断打开过的页面不再执行 window.open(url, name) ,而是转而去执行window.open(‘javascript:;’, name)激活窗口

const urlname = getLocalName(url)
// 存在name的话执行激活,不执行跳转
 if (urlname) {
  window.open('javascript:;', urlname)
  return
}

// 执行首次跳转
window.open(url, name)
// ...上方代码

4.2.3 给窗口命名

当通过window.open打开某个页面后,自动给窗口命名,名字的来源来自于localStorage,还是因为同域的关系,共享了localStorage,我们可以通过当前的网址去localStorage做匹配,匹配到网址后取到对应的key,这个key就是窗口的名字,将其赋值给窗口

function loadWidName(url) {
  const newUrl = getLocalName(url)
  window.name = newUrl
}

function getLocalName(url) {
  let local = localStorage.getItem(localStorageKey)
  if (!local) return false

  local = JSON.parse(local)

  // return Object.prototype.hasOwnProperty.call(local, key);
  let name = ''
  for (const key in local) {
    if (!Object.prototype.hasOwnProperty.call(local, key)) continue

    if (local[key] === url) {
      name = key
      break
    }
  }
  return name
}

注意的是,loadWidName这个函数得在页面一加载就执行,因为必须得在执行open之前就给窗口命名成功,否则执行open的时候会认为当前页面没有被打开过,直接进行跳转了;

4.3 缓存的问题

在想想,仔细想想,缓存的问题是不是已经被解决掉了,缓存最大的困难是什么,是窗口的命名,一旦进行刷新窗口的名字就丢失了,因此在别的窗口执行 window.open('javascript:;', item.title) 的时候会找不到带有这个名字的窗口;
而如果在一加载页面的时候就执行了上面4.2.3这个方法,去主动给窗口命名,那么刷新的时候自然也会去执行这个命名的过程,自然再怎么刷新窗口的name值一直是保持有的;
缓存的问题除了主动给窗口命名还剩下的就是关闭窗口是去 移除对应缓存 了,如果不移除,那么把窗口关闭后在其他窗口中点击关闭窗口时,会认为该窗口依然处于打开状态,那就会去执行window.open('javascript:;', urlname),打开一个空白页面~
移除代码很简单,给window添加一个beforeunload事件

window.addEventListener('beforeunload', function () {
    let local = localStorage.getItem("demo")
    if (!local) return false
  
    local = JSON.parse(local)
    const newItem = {}
    for (let item in local) {
      if (item !== key) {
        newItem[item] = local[item]
      }
    }
    localStorage.setItem("demo", JSON.stringify(newItem))
  return
})

到这里基本就实现了这个功能了

五、代码下载

代码已经上传到CSDN上了,由于是正式使用的我简单压缩了一下,下载地址如下:前端window.open实现激活而非打开的功能;
如果有需要源码的小伙伴留言或者私信留下邮箱,博主看到后会及时发送的~问题不大
至于使用也非常简单,在main.js中引入文件,这个文件扩展了一个类似于 window.open() 的方法,所有执行 window.open() 的地方改用我们的方法代替,在方法内部去判断是新建窗口还是激活窗口,比如

// main.js
import openUrl from "xxx"

// 使用时在内部实现逻辑判断是新建还是激活
window.openUrl(url,title) 代替 winow.open(url,title)

六、小结

本文主要解决了在类似Vue的单页应用项目中,在任意一个窗口内首次打开指定页面时通过新建窗口的方式打开,在任意一个窗口内打开已打开的界面时,仅激活对应窗口的场景功能;
这个场景可能比较冷门,但确实真实存在并被我司的小伙伴遇到了,当然博主这种方法是不是最优解不太清楚,如果有小伙伴知道更优的方式,一定,一定记得留言告诉博主,谢谢~
如果有帮助,点个赞,点个关注吧~谢谢文章来源地址https://www.toymoban.com/news/detail-759453.html

到了这里,关于论多窗口相互关联下window.open打开已在的窗口时只激活不刷新的实现方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity 打开Windows文件窗口

    Github:ookii-dialogs-winforms,下载后缀为nupkg的文件,修改后缀为rar,解压打开找到 Ookii.Dialogs.WinForms.dll Assets目录下新建css.rsp文件,文件内容为: -r:System.Windows.Forms.dll API等级调整为.NET Framework Unity版本2021.3.6f1c1

    2024年02月12日
    浏览(65)
  • JS打开新标签页(window.open应用)

    在 a标签 中通过设置target=”_blank”就可以实现打开新标签的效果。但有时候我们需要通过Javascript来打开新标签,那么怎么实现呢? 方法如下: window.open(“http://www.wlzhys.com“); 或者: window.open(“http://www.wlzhys.com“, “_blank”); //注意第二个参数 注意事项: 在IE中,如果要打开

    2024年02月16日
    浏览(49)
  • python --根据windows窗口名称、进程pid打开窗口(pygetwindow详解)

    简介: pygetwindow 是一个Python库,用于获取、操作和管理当前打开的窗口。它提供了一些常用的窗口操作方法,包括获取窗口句柄,获取窗口位置和大小,移动和调整窗口大小,最小化、最大化和还原窗口,以及模拟输入和焦点控制等。 安装 详解 获取当前所有窗口 获取指定标

    2024年02月07日
    浏览(81)
  • 浏览器window.open()用法,以及利用其实现拦截弹出式窗口

    open() 方法用于打开一个新的浏览器窗口或查找一个已命名的窗口。 window.open( URL,name,specs,replace ) 参数 说明 URL 可选。打开指定的页面的URL。如果没有指定URL,打开一个新的空白窗口 name 可选。指定target属性或窗口的名称。支持以下值: _blank - URL加载到一个新的窗口。这是默

    2024年02月09日
    浏览(38)
  • Windows 打开cmd/dos窗口的12种方式(全网最全)

    最近在写某个批处理脚本时,意外发现 Windows系统中,在不同路径打开的cmd/dos窗口,属性配置竟然不同,接下来就一起来探究下。 (以下演示在Win10系统,其他版本系统可能会有不同; cmd窗口/dos窗口/命令提示符窗口,不用纠结叫法) 今天先来总结下打开cmd/dos窗口都有哪些

    2024年02月09日
    浏览(32)
  • vue中使用window.open打开assets文件夹下的pdf文件

    需求:系统有个操作手册,点击会在浏览器新开个窗口并打开pdf文件。这个pdf文件存储在本地assets文件夹中。 文件结构: 注:直接使用window.open(文件路径)不能打开,需要在vue.config.js中配置所需文件 引入图中红框中的代码 页面中打开:(我是在初始化的时候就打开文件,没

    2024年02月10日
    浏览(60)
  • [ Windows 10 ] 任务栏按钮不显示正在打开的窗口了(打开任何程序任务栏图标按钮都不显示)

    系统是Windows 10 professional版本,在一次突然开机后,发现点开程序后,在任务栏什么都不显示,任务栏按钮和图标状态均不显示了,但是程序在运行。 当时兄弟们我心态直接蹦了啊,100万个草泥马根本停不下来,口里不断重复学习英文单词: what\\\'s the f**king going on? 异常情况如

    2024年02月04日
    浏览(50)
  • Python打开Windows可执行性程序的几种方法(Windows窗口自动化第一步)

    方法一:用Pywinauto第三包 方法二:使用os.system函数运行其他程序 方法三:win32api第三包使用ShellExecute函数运行其他程序 方法四:使用win32process.CreateProcess函数 方法七:用ctpyes模块调用C函数

    2024年02月16日
    浏览(58)
  • Java实现Windows任务栏图标闪烁功能,托盘图标闪烁,点击任务栏打开Java窗口

      JFrame 是指一个计算机语言-java的GUI程序的基本思路是以JFrame为基础,它是屏幕上window的对象,能够最大化、最小化、关闭。 GUI主要功能是实现人与计算机等电子设备的人机交互。它是用户与操作系统之间进行数据传递和互动操控的工具,用户可以通过一定的操作实现对电子

    2024年01月24日
    浏览(38)
  • js关闭当前窗口报错Scripts may close only the windows that were opened by them

    在 Chrome 浏览器中调用 window.close() 关闭当前页面时浏览器控制台报出 Scripts may close only the windows that were opened by them. 且无法关闭当前页面。 先上结论 :不是通过 JS 打开的浏览器标签,都不能通过 window.close() 来关闭当前页面 MDN 对于 window.close() 的解释如下所示: 文章里说,

    2024年01月20日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包