遇到一个有趣需求,需要将页面内的一些链接按照规则判断是否需要打开新的窗口或使用已存在的窗口,如:当前存在的链接格式为 www.autohome.com.cn/[path]/[x]...., 当path
相同时,使用已存在的窗口打开新的页面,否则打开新的窗口。
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>
标签的 target
同 window.open
的 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}
>
<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,我们的需求已经实现了。分享就到这里,希望对你有所帮助。