重新认识window.open与标签页通信实践

最近要把之前的打包下载改成后台下载,所谓后台,就是要新打开一个浏览器页签,在页签进行下载,我需要把文件信息传过去,这就涉及到了页签之间的通信,我选择了BrodcastChannel,其实有很多通信的方式,并不是BrodcastChannel有多优秀,而是我一百度就搜到了吗,看到了我就直接用了,没对比过其他的,大家可以去看看别的方法。

可能这也不是多难的需求,但是我之前没做过,也踩了坑,没准还可以帮助一下路过的人,所以记录一下。
我的思路是点击下载按钮,使用window.open()打开新页签,这个方法的返回值是新页签的window对象,window对象中的closed属性和focus方法比较关键,closed的值是布尔值,代表这个窗口是否已经关闭。调用focus可以聚焦到当前窗口。

js 复制代码
主页面

let newWindow = null //用于存放新打开页签的window
const BC = new BrodcastChannel('BC_NAME') //new一个BC
const downLoadFile = ()=>{
   //如果newWindow没有值或者newWindow.closed是true,说明新页签从来没打开过,或者已经关闭了
   //这种情况就重新打开新页签
   if(!newWindow || newWindow.closed){
      newWindow = window.open(newWindowUrl)
      newWindow.onload = ()=>{
         //在新页面加载完毕时发送消息
         BC.postMessage('message')
      }
   }else{
   //newWindow.closed为true走到这里
   //发送消息,聚焦过去
   BC.postMessage('message')
   newWindow.focus()
   }
}

好像这个需求就快快乐乐的结束了,剩下的写写业务代码完事了,但是我在原页签点击了刷新,什么变量什么BC都会消失,而且window也无法存进storage,我该如何是好,我即无法判断新页签的状态,也无法使用focus聚焦。 所以聪明的我准备使用localstorage标记状态,window.open之后我就setItem,新页签销毁时我就removeItem,这样不就可以判断状态了吗。果然是我。那怎么聚焦呢,我在消息中加一个标识,用来判断是不是第一次打开,下载页面接收到消息时判断一下是不是第一次打开,如果不是,那就调用一下focus不就完了吗,就酱紫。

js 复制代码
主页面

const BC = new BrodcastChannel() //new一个BC
const downLoadFile = ()=>{
   //如果flag没有值,说明新页签从来没打开过
   //这种情况就重新打开新页签
   const flag = localStorage.getItem('flag') //取一下这个状态
   const data = {msg:'message',first:flag} 
   const params = JSON.stringify(data)
   if(!flag){
     const newWindow = window.open(newWindowUrl)
      newWindow.onload = ()=>{
         //在新页面加载完毕时发送消息
         localStorage.setItem('flag','down')
         BC.postMessage(params)
      }
   }else{
   //flag有值走到这里
   //发送消息,聚焦过去
   BC.postMessage(params)
   }
   
}
js 复制代码
下载页面

onMounted(()=>{
  const BC = new BrodcastChannel('BC_NAME') //new一个BC,建立通道
  BC.onmessage = ({data})=>{
      const {msg,first} = JSON.parse(data)
      ......处理数据不写了
      //如果有flag调用focus
      first&&window.focus()
  }
})
onUnmounted(()=>{
  localStorage.removeItem('flag')
})

单纯的我以为这样就可以了,但是window.focus失效了,这是为什么,我急忙打车去问ChatGtp,他是这样说的。

估计是因为中了第三点的原因,不过发现这个问题的同时我也发现了另一个华点。 window.open的完全体 window基本语法window.open(URL, windowName, windowFeatures); 我发现他可以通过名字跳转页面,只要第二个参数传递新页签的名字就好了,那我何必拘泥与focus呢,最终:

js 复制代码
主页面

const BC = new BrodcastChannel() //new一个BC
const downLoadFile = ()=>{
   //如果flag没有值,说明新页签从来没打开过
   //这种情况就重新打开新页签
   const flag = localStorage.getItem('flag') //取一下这个状态
   if(!flag){
     const newWindow = window.open(newWindowUrl,'myWindow') //这里可以定义新页签的名字
      newWindow.onload = ()=>{
         //在新页面加载完毕时发送消息
         localStorage.setItem('flag','down')
         BC.postMessage('message')
      }
   }else{
   //flag有值走到这里
   //发送消息,聚焦过去
   BC.postMessage('message')
   window.open('javascript:;','myWindow') 
   //至于为什么url那里写'javascript:;'我也不清楚,我是百度的,有知道的可以留言
   }
   
}

文章中的描述和代码都是在掘金页面敲的,没有代码提示可能有错别字或者写错的地方,大家发现了给我留言哦。

相关推荐
小old弟3 分钟前
jQuery写油猴脚本报错eslint:no-undef - '$' is not defined
前端
Paramita3 分钟前
实战:使用Ollama + Node搭建本地AI问答应用
前端
一天睡25小时4 分钟前
前端の骚操作代码合集 (二)| 让你的网页变得有趣
前端·javascript
王林不想说话6 分钟前
Zustand状态管理库
前端·javascript
清风ai明月7 分钟前
vue模板语法中使用冒号: 什么时候使用,什么时候不使用呢?
前端·javascript·vue.js
少卿8 分钟前
uniapp run使用指南 - VSCode 开发 Uni-app 项目
前端·vue.js
咪库咪库咪9 分钟前
css进阶:flex
前端
xcsweb10 分钟前
用AI理解前端文件类型
前端
剑亦未配妥11 分钟前
Vue2函数式组件实战:手写可调用的动态组件,适用于toast轻提示、tip提示、dialog弹窗等
前端·vue.js·vue
Enddme11 分钟前
带你了解面试常被问到的ES6+的核心新特性
前端·javascript