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

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

相关推荐
格尔曼Noah4 小时前
Safari浏览器中如何只允许指定网站下载
前端·safari
用户059540174465 小时前
用了3年Redis,才发现我一直没搞懂缓存一致性测试
前端·css
swipe5 小时前
07|(前端转后全栈)为什么后端也要缓存?从前端缓存思维理解 Redis
前端·后端·全栈
IT小盘5 小时前
05-企业项目统一接入多个大模型-适配器模式实战
前端·人工智能·适配器模式
swipe5 小时前
06|(前端转后全栈)登录后端到底在做什么?JWT、Spring Security 和权限链路
前端·后端·全栈
海上彼尚6 小时前
Nodejs也能写Agent - 22.LangGraph篇 - 上下文工程
前端·javascript·人工智能·langchain·node.js
阳光是sunny6 小时前
LangGraph实战教程:预定义状态MessagesState与AgentState
前端·人工智能·后端
muddjsv7 小时前
CSS选择器体系精讲:按身份、结构、状态精准匹配元素(零基础吃透)
前端·css
GuWenyue7 小时前
等AI回复卡顿到劝退?Vue3+DeepSeek流式输出实战,70行代码实现打字机效果
前端·人工智能·客户端