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

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

相关推荐
一个很帅的帅哥16 分钟前
axios(基于Promise的HTTP客户端) 与 `async` 和 `await` 结合使用
javascript·网络·网络协议·http·async·promise·await
dream_ready1 小时前
linux安装nginx+前端部署vue项目(实际测试react项目也可以)
前端·javascript·vue.js·nginx·react·html5
编写美好前程1 小时前
ruoyi-vue若依前端是如何防止接口重复请求
前端·javascript·vue.js
flytam1 小时前
ES5 在 Web 上的现状
前端·javascript
喵喵酱仔__1 小时前
阻止冒泡事件
前端·javascript·vue.js
GISer_Jing1 小时前
前端面试CSS常见题目
前端·css·面试
某公司摸鱼前端1 小时前
如何关闭前端Chrome的debugger反调试
javascript·chrome
八了个戒1 小时前
【TypeScript入坑】什么是TypeScript?
开发语言·前端·javascript·面试·typescript
不悔哥2 小时前
vue 案例使用
前端·javascript·vue.js
anyup_前端梦工厂2 小时前
Vuex 入门与实战
前端·javascript·vue.js