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

相关推荐
RePeaT12 小时前
【Next.js】基础知识速查
前端·react.js·next.js
M ? A15 小时前
Vue v-bind 转 React:VuReact 怎么处理?
前端·javascript·vue.js·经验分享·react.js·面试·vureact
Tisfy17 小时前
CORS 跨域重定向后 Origin 变 null —— 一次 Nginx 字体加载失败的排查记录
运维·nginx·html·cors
Ruihong18 小时前
你的 Vue KeepAlive 组件,VuReact 会编译成什么样的 React 代码?
vue.js·react.js·面试
Ruihong18 小时前
你的 Vue slot 插槽,VuReact 会编译成什么样的 React 代码?
vue.js·react.js·面试
fqrj202618 小时前
什么是WordPress?企业WordPress搭建网站的基本流程和步骤分享
html·wordpress·网站开发·技术开发
暗不需求19 小时前
React新手小白:如何入门 React 响应式交互与 JSX 艺术
前端·react.js
前端缘梦19 小时前
深入理解React Fiber架构:渲染流程与双缓冲机制全解析
前端·react.js·面试
Ruihong19 小时前
Vue v-slot → 用 VuReact 转换后变成这样的 React 代码
vue.js·react.js·面试
Ruihong19 小时前
你的 Vue v-model,VuReact 会编译成什么样的 React 代码?
vue.js·react.js·面试