在HTML中如何在一个新窗口打开多个的页面

遇到一个有趣需求,需要将页面内的一些链接按照规则判断是否需要打开新的窗口或使用已存在的窗口,如:当前存在的链接格式为 www.autohome.com.cn/[path]/[x]...., 当path相同时,使用已存在的窗口打开新的页面,否则打开新的窗口。

graph TD A[用户点击链接] -->|判断是否存path的窗口| B(存在) A -->|不存在| C(打开新的窗口) B -->|path相同| D(使用已存在的窗口打开新的页面) B -->|path不同| C

1. 使用window.open打开新的窗口

window.open 是我们熟知打开新的窗口的方法。open(url, target, windowFeatures) 方法第一个参数url是要打开的URL,第二个参数target是窗口的名字,第三个参数windowFeatures是窗口的属性。更多信息查看MDN

1.1 target参数

target 一个不含空格的字符串,用于指定加载资源的浏览上下文的名称。如果该名称无法识别现有的上下文,则会创建一个新的上下文,并赋予指定的名称。还可以使用特殊的 target 关键字:_self_blank_parent_top该名称可用作 <a> 或 <form> 元素的 target 属性。

tsx 复制代码
const article = [{
  title: 'A 路径 / 1.html',
  path: 'https://www.autohome.com.cn/A/1.html',
}, {
  title: 'B 路径 / 1.html',
  path: 'https://www.autohome.com.cn/B/1.html',
}, {
  title: 'A 路径 / 2.html',
  path: 'https://www.autohome.com.cn/A/2.html',
}, {
  title: 'B 路径 / 2.html',
  path: 'https://www.autohome.com.cn/B/2.html',
}]

export default function App() {
  return (
    <ul>
      {article.map((item) => {
        return (
          <li
            key={item.path}
            onClick={() => {
              {/* window.open 的第二个参数 target 将会为 "A" 或 "B" */}
              window.open(item.path, new URL(item.path).pathname.split('/')?.[1])
            }}
          >
            {item.title}
          </li>
        );
      })}
    </ul>
  );
}

分别点击以上的链接,我们会发现,当点击第一个和第三个链接时,会在同一个窗口打开页面,而点击第二个和第四个链接时,会在同一窗口打开新的页面。点击上面所有链接后,我们会发现,浏览器只新打开了两个窗口。

2. 使用<a>标签打开新的窗口

使用 window.open 会对SEO(搜索引擎优化)有一些影响,因为使用 window.open 打开的页面,搜索引擎不会对其进行抓取。所以我们期望可以使用 <a> 标签的 target 属性来打开新的窗口。

2.1 <a> 标签的 target 属性

我们熟知的 <a> 标签的 target 属性有以下几个值:

  • _self 默认值,当前窗口打开
  • _blank 新窗口打开
  • _parent 父窗口打开
  • _top 顶层窗口打开

MDN 中介绍 windown.open 中的 target 参数中我们可以看到 target参数名称可用作 <a> 或 <form> 元素的 target 属性。, <a> 标签的 targetwindow.opentarget 参数一样,可以指定一个窗口的名字。

tsx 复制代码
const article = [{
  title: 'A 路径 / 1.html',
  path: 'https://www.autohome.com.cn/A/1.html',
}, {
  title: 'B 路径 / 1.html',
  path: 'https://www.autohome.com.cn/B/1.html',
}, {
  title: 'A 路径 / 2.html',
  path: 'https://www.autohome.com.cn/A/2.html',
}, {
  title: 'B 路径 / 2.html',
  path: 'https://www.autohome.com.cn/B/2.html',
}]

export default function App() {
  return (
    <ul>
      {article.map((item) => {
        return (
          <li
            key={item.path}
          >
            <a
              href={item.path}
              {/* 这里的 target 将会为 "A" 或 "B" */}
              target={new URL(item.path).pathname.split('/')?.[1]}
            >
              {item.title}
            </a>
          </li>
        );
      })}
    </ul>
  );
}

结果是可喜的,点击所有链接后,浏览器只新打开了两个窗口。

封装成一个组件

接下来我们考虑将这个功能封装成一个组件。解决一下 target="A"target="B" 属性暴露以及target生成方法优化。

tsx 复制代码
// 简单的封装
export default function ALink(props: {
  children: React.ReactNode;
  href: string;
  [key: string]: any;
}) {
  const { children, href, target = '_self' } = props;
  return (
    <a
      href={props.href}
      target={props.target}
      onClick={(e) => {
        e.preventDefault();
        if(target != '_blank') {
          window.open(href, target);
        } else {
          window.open(href, new URL(href).pathname.split('/')?.[1]);
        }
      }}
    >
      {children}
    </a>
  );
}
tsx 复制代码
// 使用
import ALink from './ALink';

const article = [{
  title: 'A 路径 / 1.html',
  path: 'https://www.autohome.com.cn/A/1.html',
}, {
  title: 'B 路径 / 1.html',
  path: 'https://www.autohome.com.cn/B/1.html',
}, {
  title: 'A 路径 / 2.html',
  path: 'https://www.autohome.com.cn/A/2.html',
}, {
  title: 'B 路径 / 2.html',
  path: 'https://www.autohome.com.cn/B/2.html',
}]

export default function App() {
  return (
    <ul>
      {article.map((item) => {
        return (
          <li
            key={item.path}
          >
            <ALink
              href={item.path}
              target="_blank"
            >
              {item.title}
            </ALink>
          </li>
        );
      })}
    </ul>
  );
}

看下在浏览器中的效果:

Nice,我们的需求已经实现了。分享就到这里,希望对你有所帮助。

相关推荐
朝阳391 小时前
React【面试】
前端·react.js·面试
漓漾li1 小时前
每日面试题(2026-05-15)- 前端
前端·vue.js·react.js
向阳而生6602 小时前
iframe 使用全解析:语法、避坑与实操指南(新手友好)
html
用户600071819102 小时前
【翻译】在 React Router 中理清对话框
react.js
a1117764 小时前
细胞结构实验室(react 开源)
前端·javascript·开源·html
产品经理爱开发6 小时前
老师用AI开发的HTML教具如何在线托管访问
前端·html·ai编程·持续部署·源代码管理
光影少年6 小时前
react的 useState 原理、批量更新机制
前端·react.js·掘金·金石计划
ZC跨境爬虫7 小时前
跟着MDN学HTML_day_47:(Document接口)
前端·javascript·ui·html·ecmascript·音视频
Swift社区7 小时前
Flutter / React / ArkUI:在鸿蒙 PC 上怎么选?
flutter·react.js·harmonyos
学习论之费曼学习法7 小时前
ReAct框架深度解析:让Agent会思考再行动
前端·react.js·前端框架