当前位置:网站首页>你的 Link Button 能让用户选择新页面打开吗?
你的 Link Button 能让用户选择新页面打开吗?
2022-08-09 21:54:00 【InfoQ】
我是HullQin,公众号「
线下聚会游戏
」的作者
(欢迎关注公众号,联系我,交个朋友)
,转发本文前需获得作者HullQin授权。我独立开发了
《联机桌游合集》
,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费无广告。还独立开发了
《合成大西瓜重制版》
。还开发了
《Dice Crush》
参加Game Jam 2022。喜欢可以关注我噢~我有空了会分享做游戏的相关技术。
1. 什么是Link Button?
我想表达的是「
需要导航能力的可点击元素
」(Link Button是为了方便沟通而创造的名词)
我用Link表示
导航能力
,用Button表示
可点击元素
。
什么是导航能力?
切换路由(URL)的能力。
<a>
标签因为
href
属性,天然具备导航能力。而
<button>
标签没
href
,只能在
onclick
事件中,用JS控制打开新页面。
2. 用户怎么选择新页面打开?
分2种情况,你可以在掘金页面试一下:
2.1 新标签页(tab)打开
Command
(Mac)/Ctrl
(Windows) + 鼠标左键click
- 鼠标中键click
- 鼠标右键click,在菜单选择“在新标签页中打开链接”
- (无障碍)通过
Tab
,选中链接时,按Command
(Mac)/Ctrl
(Windows) + 回车键Enter
2.2 新窗口(window)打开
Shift
+ 鼠标左键click
- 鼠标右键click,在菜单选择“在窗口中打开链接”
- (无障碍)通过
Tab
,选中链接时,按Shift
+ 回车键Enter
3. 什么是极致的用户体验?
一切导航功能,都应该给用户完整的『新窗口』打开能力。
只要你的按钮会导致页面切换,就应该允许用户
用1.2提到的任意方式,在新页面打开
。
4. 如何优雅的实现“Link Button”
4.1 新手方案:
<button>
+
onclick
我刚学前端时,常常喜欢用
<button>
实现导航功能,只要在
onclick
里写
window.open(url)
或
window.document.href = url
或
window.location.replace(URL)
就好了。
缺点很明显
- 用户根本无法选择在新页面or本页面打开,只能接受你的实现。
- 用户根本不知道点击按钮后会发生什么。(如果是
<a>
标签,用户hover时,会在浏览器左下方看到新页面 URL)
4.2 中手方案:
<button>
+
onclick
+
event
工作2个月后,我懂了点用户体验,但知识局限于:用户点击
Command
(Mac)/
Ctrl
(Windows) + 鼠标左键click,可以新标签页打开。所以我这么写:
// buttonElement 是html中某个<button>元素
buttonElement.onclick = function (event) {
if (event.ctrlKey || event.metaKey) {
window.open('某个url');
} else {
window.document.href = '某个url';
}
};
触发
onclick
时,通过
event
参数判断下有没有按下
Ctrl
或
Command
:如果有按下,就新标签页打开;否则本页面跳转。
其实这种方案只比新手方案好一点点,问题没有得到根本解。
4.3 高手方案:
<a>
+
onclick
+
event
工作半年后,同事告诉我中键click也能新标签页打开。我又学了点html无障碍规范,才明白一个道理:
导航能力,就交给专业的
<a>
标签做,兼容性最好,能力最全面。
<a>
除了
天然支持新页面打开
,还有些好处:鼠标Hover上去时,浏览器会提示新页面地址,并且也能直接右键复制地址,便于分享!
但是!有2个问题需要解决:
4.3.1 样式问题
<button>
和
<a>
样式是有差异的。产品形态上希望用按钮,我们就不能用超链接样式。
该问题很好解,把你按钮样式复制一份,或者把相关class放到
<a>
标签上,就基本一样了,如果还有样式差异,就再覆盖一下
<a>
的默认样式(大多数浏览器会给它设置字体颜色、下划线这2个默认样式):
a, a:link, a:visited, a:hover, a:active {
color: inherit;
text-decoration: none;
}
4.3.2 JS逻辑问题
如果导航,需要其它JS逻辑,就无法只用
<a>
和
href
实现,并且这种情况还不少。例如:
- 跳转时,需要传路由state。
- 某些逻辑,只希望本页面跳转时执行,不允许新页面打开时执行(因为JS只能执行本页面的JS,如果在新页面打开,本页面应该保持不变,不能执行那段JS,例如React Router中的
<Link>
)。
- 某个按钮,直接点击时是
window.history.back()
,但也允许新窗口打开上个页面地址(这个问题更加复杂,请期待我的下篇文章,会做详细讲解)
现在我想告诉你:
这些问题,也是有解的!
这些问题的解决方案
还记得我曾经是个“中手”吗?我的“中手方案”刚好可以解决这个难题!把中手方案逻辑改改,就可以了:
// aElement是html中的某个包含href的<a>元素: <a href="某个url">某个链接</a>
aElement.onclick = function (event) {
if (event.button !== 0) return;
if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return;
event.preventDefault();
// 如果用户期望本页面跳转(而非新窗口打开),则执行以下逻辑
window.history.pushState({ pageState: 123 }, '', 'new-page.html');
};
解释下:
event.button
表示按下的是鼠标哪个按键:
- 0:主按键,通常指鼠标左键或默认值
- 1:辅助按键,通常指鼠标滚轮中键
- 2:次按键,通常指鼠标右键
- 3:第四个按钮,通常指浏览器后退按钮
- 4:第五个按钮,通常指浏览器的前进按钮
这里我们只管理左键就好,其它按键都保持浏览器默认行为(所以非0直接return,不执行JS逻辑,执行原生行为)。
event.xxxKey
event.ctrlKey
: MAC上表示Control键,Windows上表示Ctrl键。
event.metaKey
: MAC上表示Command键,Windows上表示Windows键。
event.shiftKey
: Shift键。
event.altKey
: MAC上表示Option键,Windows上表示Alt键。
按照规范,这些键按下时,不应该在本页面继续跳转,而是会发生这些事:
ctrlKey
+click
: Mac上表示右键点击该元素,Windows上表示新标签页打开页面。
metaKey
+click
: Mac上表示新标签页打开页面,Windows上打开Windows开始菜单。
shiftKey
+click
: 新窗口打开页面。
altKey
+click
: 下载页面。
event.preventDefault()
如果用户只是普通的左键点击了链接,没按任何xxxKey,就应该阻止
<a>
标签默认行为,由我们的JS去接管,自由操控跳转。
但如果用户按了任何xxxKey,或是点了鼠标其它键,都应该让
浏览器接管后续逻辑
。
Oh!真是完美的方案!
5. 写在最后
如果你像我一样,喜欢代码
纯粹
一点,不夹杂冗余功能,就可以自己写Link Button,封装自己所需的组件。
如果你只是为了完成别人的需求,还是直接用组件库吧。
但是,即使你用组件库,里面有
Menu
、
Button
组件,你一定要想清楚,如果需要页面跳转,务必找找
Link
组件,尽量使用
Link
来表达导航。
关于导航的用户体验,非常细节,太重要了!
一个网页的质量,一个前端开发者的水平,能直接从导航栏细节中看出
。
最后希望大家都能开发出用户体验完美的“Link Button”!
边栏推荐
- How do task flow executors work?
- Use zeros(), ones(), fill() methods to generate data in TF
- Flask之路由(app.route)详解
- NIO Cup 2022 Nioke Summer Multi-School Training Camp 7 CFGJ
- ACM MM 2022 | Cloud2Sketch: 长空云作画,AI笔生花
- Blender程序化建模简明教程【PCG】
- 基于ABP的AppUser对象扩展
- 《强化学习周刊》第57期:DL-DRL、FedDRL & Deep VULMAN
- AI识万物:从0搭建和部署手语识别系统
- Domestic mobile phone manufacturers once fought for it, but now it is the first to collapse...
猜你喜欢
随机推荐
宝塔实测-搭建LightPicture开源图床系统
CVPR22 Oral|通过多尺度token聚合分流自注意力,代码已开源
JS解混淆-AST还原案例
L3-2 Delete up to three characters (30 points)
为什么这么多人都想当产品经理?
数独 | 回溯-7
Multiple reasons for MySQL slow query
【EF】 更新条目时出错。有关详细信息,请参见内部异常。[通俗易懂]
2.1.5 大纲显示问题
一本通2074:【21CSPJ普及组】分糖果(candy)
Flask之路由(app.route)详解
1215 – Cannot add foreign key constraint
How to Make Your Company Content GDPR Compliant
Leetcode 93 复原IP地址
发送激活邮件「建议收藏」
Jinshanyun earthquake, the epicenter is in bytes?
TF中使用zeros(),ones(), fill()方法生成数据
POWER SOURCE ETA ETA Power Repair FHG24SX-U Overview
Cookie、session、token
Flask introductory learning tutorial