重新认识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:;'我也不清楚,我是百度的,有知道的可以留言
   }
   
}

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

相关推荐
阿伟来咯~10 分钟前
记录学习react的一些内容
javascript·学习·react.js
吕彬-前端15 分钟前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱18 分钟前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai27 分钟前
uniapp
前端·javascript·vue.js·uni-app
也无晴也无风雨28 分钟前
在JS中, 0 == [0] 吗
开发语言·javascript
bysking1 小时前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
王哲晓2 小时前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_4112 小时前
无网络安装ionic和运行
前端·npm
理想不理想v2 小时前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云2 小时前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js