加上快捷键,让你的网站酷起来

news/2024/5/11 17:56:48/文章来源:https://blog.csdn.net/qq_33159055/article/details/50396278

伟大的程序员都懒。

这话是我从《PHP 与 MySQL 程序设计》中看来的,来自于 Larry Wall 的一句话:

Most of you are familiar with the virtues of a programmer. There are three, of course: laziness, impatience, and hubris.

懒的程序员的特征是:能花一步完成的事绝不花两步,即便花一步那一步的时间也是越少越好。所以他们做了很多工具来快捷完成一些繁琐耗时长的任务;放到 Web 上,就有人做了快捷键;这个技术难度并不高,但是把一些非常频繁的操作利用快捷键来触发的话,速度会快不少;毕竟,用鼠标在屏幕上定位一个点然后点击,是比定位键盘按键速度慢的。

下图分别是 Github、Facebook、Twitter、微博、知乎、Gitlab 的快捷键,不知道你以前有没有注意过,如果没有,下次打开这些网站的时候,在页面中输入「?」试试。


键码与键名的映射表

首先你需要定义一张键码与键名的映射表:因为我们在文档上监听键盘相关的事件,keyupkeydown,事件触发时根据我们获取的事件对象,能让我们判断是哪个按键的,只有事件对象的whichkeyCode属性,而这都是以键码给出的,并不直观,尤其是在插件完成后注册快捷键时,非常不容易记忆和理解;

把你希望构成快捷键组合的所有按键,全部存进映射表中,可用如下方式给出:

var keyCode2keyName = {  
9:'tab',
32:'space',
191:'?',
187:'+',
189:'-',
13:'enter'

}
for(var i = 65;i<91;i++){keyCode2keyName[i] = String.fromCharCode(i).toLowerCase(); }

在后续的程序中必要的时候,我们都需要把获取到的键码转换成键名,方便理解。

思路

实际上,我们要解决的最主要的两个大问题:判断按键组合,触发组合事件;通俗地说就是:如何获取用户按下的快捷键(或者组合);用户按下组合按键后如何触发事件。

判断按键组合

我之前一直说的是按键组合,但其实不一定要全部定义多个按键按下才能触发快捷功能,我们完全可以定义某个单个按键被按下时就触发某个行为;总体来说,各个实现了快捷键功能的网站,快捷键种类有以下三种:

  • 单个按键触发:比如jk;按j选择下一个列表项,k选择上一个列表项(可能灵感来自 VIM 编辑器);

  • 带修饰键的单个按键触发:修饰键指的是shiftcontrolcommandalt等等,通常在一个键盘事件触发时,自动生成的事件对象中,会有专门的属性指明某个修饰键是否被同时按下,其属性值是个布尔值;

  • 多个按键的触发:这里多个按键特指多个非修饰键的按键组合,比如g+m,意味着按下g键之后继续按下m键的组合;

当我们想做一个比较合格的插件时,需要能够处理以上三种情况;以及这三种情况的冲突解决。这里的冲突的指的是:假如我们既定义了a执行某个功能Fa,又定义了b+a执行某个功能Fb,那么当用户按下b键之后继续按下a键,那么程序应当如何响应?是执行Fa还是Fb或者是两者都执行。
我的建议是:在注册快捷键,尽量避免这样的冲突;如果实在无法避免,那这种情况下必须执行Fb,因为如果连用户已经按了多个按键,程序还不触发组合按键事件,那组合快捷键就永远捕获不到了;优先捕获按键组合,其次捕获单个按键。

在 Bugtags 网站上有一个快捷键组合m+y,可以快捷跳转到所有指派给「我」完成的问题;后面的叙述以这个例子来说明。

在快捷键的触发过程中,当某个按键被按下时,我们需要获取它与当前被按下的其他按键所能构成的组合。所以必然需要一个变量pressedKeys(数组)来保存任意时刻被按下的按键,因此我们需要监听keyupkeydown事件;

keydown时,逻辑稍微复杂点,并且这也是整个快捷键功能的核心;
在某个按键按下时,需要考察当前按键和已经按下的其他按键,看看会构成哪些按键组合(拼接按键组合字符串,作为激活事件的依据):
keydown事件中只需要专门捕获按键组合,而不用考虑这个按键或者按键组合是否已经定义了执行某个方法。然后把捕获的组合传入另一个方法handleKeyCombination,由他来查找这个按键组合是否定义,以及执行已定义的回调。举个例子:

  1. 假如先按下a,没有其他按键在这之前被按下,按键组合就是a,同时a存入pressedKeys,执行handleKeyCombination传入a

  2. 继续按下m,构成按键组合a+mm存入pressedKeys,执行handleKeyCombination传入a+m

  3. 然后当y被按下时,当前按键跟已经按下的其他按键构成的组合包括a+ym+y,如果按照严格一点的检测方式,只跟当前按键最近的一次按键匹配,就是m+y,如果你需要定义三个按键的组合快捷键,那当前的按键组合是a+m+y。(不过通常来说,两个按键的组合就已经够用了);
    然后仍然要把当前键码存入pressedKeys中;但是有一个特例:那就是修饰键。修饰键最好定义成与非修饰键的组合构成快捷键,在按住一个非修饰键时,我们可以通过查询事件对象来判断某个修饰键是否按下,而不需要通过前述的pressedKeys;因此按下修饰键并不需要保存到pressedKeys里;在 Bugtags 网站中,采用了严格的检测方式,执行handleKeyCombination传入m+y

keyup时,事情就简单多了,把相应的键码从pressedKeys中删除即可。

var pressedKeys = [];

// 核心逻辑都要在 keydown 事件的回调中处理
// 注:文中的代码全部依赖 jQuery;

$(document).on('keydown',function(e){
var key = '';
// 这里采用严格的检测方式,在所有与当前按键同时按下的键中,只选择最近按下的与当前按下的进行组合,即pressedKyes数组的最后一项if(pressedKyes.length){key = keyCode2keyName[pressedKeys[pressedKeys.length-1]]+'+'+keyCode2keyName[keyCode];}else{
// 如果 pressedKeys 是空数组,说明没有其他按键被按下;此时检查修饰键是否按下;if(e.shiftKey) key = 'shift';
if(e.ctrlKey) key = key?key+'+ctrl':'ctrl';
if(e.altKey) key = key?key+'+alt':'alt';
if(e.metaKey) key = key?key+'+meta':'meta';key = key?key+'+'+keyCode2keyName[keyCode]:keyCode2keyName[keyCode];}
// 将当前按键存入 pressedKyes;pressedKeys.indexOf(keyCode)<0 && (keyCode in keyCode2keyName) && pressedKeys.push(keyCode);handleKeyCombination(key);});$(document).on('keyup',function(e){
if(pressedKeys.indexOf(e.keyCode)>-1){pressedKeys.splice(pressedKeys.indexOf(e.keyCode),1);} })
function handleKeyCombination(key){ // 暂时留空,后文会完善}

触发组合事件

接下来就是在handleKeyCombination方法中,处理接收到的用户当前的按键组合,查询这个组合是否定义了回调,有就激活,没有则忽略。问题是如果这个按键组合已经定义了事件,那如何激活它呢?

要确定激活方式,就得确定事件的注册方式;我们需要实现一个事件注册方法,接受一个快捷键组合,以及相应回调;
有一种很直观的思路是这样的:注册这个组合对应的字符串为一个自定义事件,比如m+y,传入的回调就是这个事件的回调,即:

// 注册事件
function registerHotKey(key,callback){$(document).on(key,callback); }

// 触发事件
$(document).trigger(key);

然后在用户按下m以及y之后,传入这个组合,直接trigger这个事件,自然就会执行相应方法。如果是一个从未定义过回调的方法,同样trigger,只不过它没有绑定事件所以什么都不做。

但是这样会有严重的性能问题:

  1. 注册一个快捷键就得注册一个自定义事件,j是一个,k是一个,m+y是一个……这样你注册的事件会越来越多,对性能是一个比较严重的损耗;

  2. 假如你想停止使用快捷键功能,要么逐个解绑所有的快捷键事件。要么从源头上解绑 keyupkeydown相关事件。都是非常麻烦的。

统一的自定义事件

解决方法仍然是用自定义事件,不过全局我们只注册一个自定义事件,我们维持一个键值对(对象),键就是我们注册的快捷键组合,值就是当这个快捷键被触发时执行的方法。注册新的快捷键组合时,往这个对象中添加新的键值对即可。
当用户按键时,同样是将用户的按键组合传入方法,handleKeyCombination,然后我们检测用户按下的按键组合作为属性是否存在于前述对象中,如果存在则触发一个统一的事件,并传入这个组合键,让这个统一的事件去分发不同快捷键对应的方法进行执行。

var definedKeys;

// 绑定一个统一的自定义事件
$(document).on('hotkey:active',function(keyCombination){definedKeys[keyCombination].call(); })

// 注册事件
function register(key,callback){
if(!definedKeys){definedKeys = {};}
if(!(key in definedKeys)){definedKeys[key] = callback;} }

// 触发事件

function handleKeyCombination(keyCombination){
if(keyCombination in definedKeys){$(document).trigger('hotkey:active',keyCombination)} }

这样做很明显的好处是

  1. 注册新的事件时只需要操作 definedKeys 对象即可,不再需要再操作事件相关的逻辑,不再添加新的自定义事件。

  2. 可以随时解绑快捷键功能,只需要停止触发自定义的hotkey:active事件就可以了;

事件触发区域

另外还有一个需要格外注意的点是:我们监听键盘事件是绑定在整个文档对象 document 上的,但是由于浏览器的事件传播机制,如果用户在与表单交互,比如inputtextarea,用户的文字输入行为最终会冒泡到 document 上,插件如果不分情况的进行监听则很不合理的;我们需要明确区分用户确实是要在页面中输入内容和用户想触发快捷键这两种行为,因此在keydown事件中需要检测事件的target,如果是一个表单交互对象就不要触发任何事件。

另外一些需要注意的细节

  1. 快捷键的选取
    这个是仁者见仁智者见智,不过总的原则是:照顾用户习惯,好记;下面这些键跟其功能的匹配比较常用:
    kj:选择列表项上一项、下一项,这个来自于 vim 编辑器;
    :显示快捷键窗口,向用户展示快捷键的组合

  2. 页面上下文:同一套快捷键在不同的页面执行不同的功能,大部分快捷键都是有上下文,即针对某一个页面的;如果到了另一个不同的页面页面仍然触发了快捷键,执行回调需要进行容错处理;

总结

本文简述了实现一个快捷键插件的思路,并提供了核心的代码予以说明;但是这些代码片段不足以实现完整地快捷键功能,详细的代码可参考 Bugtags 的 gist(https://gist.github.com/sunlianghua/b2467f3c7e739bb169a6),Bugtags 网站中的快捷键插件就是基于这个脚本。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_880081.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用GitLab Pages托管静态网站

文章目录 前言一、GitLab Pages是什么&#xff1f;二、使用步骤1.开通账号&#xff0c;创建Git仓库同步项目2.添加.gitlab-ci.yml文件&#xff0c;开启GitLab Pages3.部署成功之后访问项目 总结 前言 在我们日常的程序员养成过程中&#xff0c;会产生一些产物&#xff0c;自己…

在12306网站上如何可以选择上中下铺

众所周知&#xff0c;在12306官方购票时无法自己选择上中下铺的&#xff0c;那么如何在12306上买到上中下铺呢&#xff0c;相信大家都会感兴趣&#xff0c;这是一个利用12306的一个web代码来实现的&#xff0c;然后结浏览器的web调式功能&#xff0c;如果你是一个web美工&#…

pc网站qq互联登录授权php版

首先看下工具类 <?php /*** QQ互联pc网页授权类*/ namespace App\Lib\QQconnect;use App\Lib\Util\Curl;class QQconnect{const err [0 >成功,100000 > 缺少参数response_type或response_type非法,100001 > 缺少参数client_id,100002 > 缺少参数client…

虚拟机内的homestead环境下的网站项目让局域网内的同事访问

# 登录进虚拟机 $ vagrant ssh # 共享本地域名 $ share apitest.cn如图红框圈住的地址就可以访问了&#xff0c;6666

怎样在织梦dedecms网站上添加漂浮广告

在织梦 dedecms的网站上添加漂浮广告其实很简单&#xff0c;这篇文章主要讲的是在织梦网站首页添加漂浮广告。 我们用本地搭建的织梦默认模板演示。 1、准备一个广告图片 准备一个广告图片&#xff0c;命名为漂浮.gif &#xff0c;设置好图片大小150*150 &#xff0c;之后把图片…

dedecms教程:多款精美分页网站模板pagelist样式

使用dedecms&#xff0c;有时需要自定义分页样式。怎么办呢&#xff1f; 不急&#xff0c;20几款精美分页样式&#xff0c;总有一款你最喜欢。使用很简单&#xff1a; 步骤&#xff1a;三步即可解决 多款精美dede分页样式.zip 1、直接覆盖include/arc.listview.class页 2、把演…

dedecms教程:网站模板自定义表单制作在线订单详细解说

一步首先你要知道自定义表单的后台界面在哪里截图 第二步添加自定义表单 我选择完全公开就是说访客提交的时候他们也是可以看到我们的自定义信息的 数据表 模板根据你的模板自定义即可 我们先look下 下面就是自定义的内容了 我随便举例给大家演示下 首先返回界面 点击红圈来添加…

dedecms教程:织梦做中英文(多语言)网站详解

对于多语言网站&#xff0c;可能许多人都想进行制作&#xff0c;可又不明白其中的道理&#xff1b;因为多语言网站不仅仅只是一个网站站点&#xff0c;具有多个而且是不同语言&#xff1b;它也不是站群&#xff0c;就是一个网站的一部分&#xff01; 首先实现多语言站点提供两种…

[原创]DEDE 织梦建站,仿站(包含5套正版建站软件)

教程包括&#xff1a; 3、dedecms仿站进门教程 本教程适用于&#xff1a; 网易博客安全提醒&#xff1a;系统检测到您当前密码的安全性较低&#xff0c;为了您的账号安全&#xff0c;建议您适时修改密码 立即修改 | 封闭 5、dedecms综合学习资料汇编&#xff1b; 重要提醒&…

简单解释网站是如何进行访问的

今天学习的时候看到一个值得记录的面试题&#xff1a; 一个网站是如何进行访问的 首先输入网址域名&#xff0c;回车&#xff1a; 1.检查本机的C:\Windows\System32\drivers\etc\hosts配置文件里有没有这个网址的域名映射 如果有&#xff0c;则直接返回对应的ip地址&#xf…

Javaweb Listener监听器的简单应用:统计网站在线人数

Listener监听器实现统计网站在线人数 开发环境&#xff1a; IntelliJ IDEA 一、什么是监听器 是指专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象&#xff0c;当被监视的对象发生变化时&#xff0c;立即采取相应的行动。 具体参考下文&#xff1a; J…

SEOER都在为网站的“流量增长优化”而迷茫

SEO优化不得不说现在做SEO的工作是非常困难的&#xff0c;而在这个行业里从业多年的SEO经理们&#xff0c;不仅仅要扛着很大的压力、还要面对下属对自己传经授教的一些期盼&#xff0c;对外更不知道搜索引擎&#xff0c;特别是百度又要干什么来剥削你的流量了&#xff01; 但其…

构建自己的网站(一)——uWSGI+Django实现显示图片点击更新

文章目录 目的说明前提遇到的问题及解决通过ip地址端口也访问不到服务器&#xff1f;域名不可用&#xff1f;域名解析后还是不可用&#xff1f;80端口没开放&#xff1f;本地实现点击切换图片djangohtml图片显示不出来&#xff1f;django服务器实现显示图片创建django项目&…

小程序打开网站小程序

呵呵&#xff0c;昨天晚上&#xff0c;快停电了&#xff0c;打开csdn &#xff0c;打开了好多的网页&#xff0c;可是 快停电&#xff0c;关网了&#xff0c;唉 &#xff01;有好多想看的网页&#xff0c;舍不得 不看&#xff0c;于是把网址 保存到一个txt文件里面&#xff0c;…

怎么使用PHP和MySQL创建个性的网站分页

分页起着重要的作用&#xff0c;在任何Web应用程序&#xff0c;具有足够大的数据被分成页。它不仅外观整洁&#xff0c;但也提高了一个网页的加载时间。所以&#xff0c;分页是很重要的一个改进的用户界面&#xff0c;并节省服务器资源。在本教程中&#xff0c;我会告诉你一个简…

谷歌的Javascript bot可以K掉你的网站

近年来由于开发商误导的企图&#xff0c;使网络更有趣的东西&#xff0c;如JavaScript和Ajax的搜索引擎不得不拿出新的工具来访问这些技术背后隐藏的内容。虽然我敢肯定&#xff0c;在Googleplex的人都没有&#xff0c;但发展背后这些先进的爬行技术最好的意图&#xff0c;他们…

转载:50个好网站,从此上网不再虚度!

《意林》&#xff0c;短小精悍的小故事&#xff0c;每次都能打动读者的心扉&#xff01;http://www.yilin.net.cn丁香园&#xff0c;一个生物学和医学专业的挚爱。http://www.dxy.cn生物谷&#xff0c;看了名字就知道是生物类的网站。http://www.bioon.com《环球科学》杂志的官…

如何在XAMPP中设置多个网站

xampp 是一个非常方便的本地 apache php mysql 的调试环境&#xff0c;在本地安装测试 WordPress 等各种博客、论坛程序非常方便。今天我们来给大家介绍一下&#xff0c;如何使用 XAMPP 在本地进行安装多个网站。 一般情况下&#xff0c;我们只需要网站程序放到 xampp/htdoc …

Linux云计算之web网站平台——LAMP

Linux Apache MySQL PHP Apache&#xff1a;实现网页共享传输 MySQL&#xff1a;实现数据存储 PHP&#xff1a;实现页面解析的解析器 浏览器&#xff1a; 仅能解析简单的HTML语言&#xff0c;无法直接解析PHP语言 部署方式&#xff1a;yum安装&#xff1a;优点&#xff1…

那些年用node接入微信走过的坑之(四)---微信扫码登录第三方网站

序言 随着微信使用者不断增多&#xff0c;很多网站使用了微信扫码登录功能&#xff0c;这里做一个简单的实现。 第三方网页授权和微信网页端授权 这两个笔者当初区分了好久&#xff0c;有什么区别和联系呢&#xff1f; 相同点&#xff1a; 两者的过程基本是类似的&#xf…