在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,我们的需求已经实现了。分享就到这里,希望对你有所帮助。

相关推荐
YFF菲菲兔17 小时前
useState 源码解析
react.js
Flynt1 天前
我的Next.js项目升级到16之后,dev倒是快了,但build差点让我回退
react.js·next.js·turbopack
光影少年2 天前
HashRouter 和 BrowserRouter 区别、底层原理、部署差异
前端·react.js·nestjs
kyriewen3 天前
我用 50 行代码重写了 React Router 核心,终于搞懂了前端路由原理
前端·javascript·react.js
ZhengEnCi3 天前
Q02-Vue-React-index.html完全指南
vue.js·react.js·html
weedsfly3 天前
JavaScript 事件流:彻底搞懂捕获、冒泡与事件委托
前端·javascript·react.js
牧艺4 天前
HTML-in-Canvas 深度解析:让 Canvas 真正「吃上」HTML 这碗饭
前端·html·canvas
爱勇宝4 天前
我给自己做了一个新标签页:不登录、不打扰、打开就能用
前端·html·浏览器
越努力越幸运665 天前
多模态代码调试实战:Gemini3.5 精准捕获 HTML 隐性语法
html
光影少年5 天前
原生DOM操作在React 中的注意事项
前端·javascript·react.js