处理击键又称快捷方式和调试

你好 我们将讨论WEBAPI + JavaScript中的热键,考虑它们的组织方法和主要在大型应用程序中出现的问题。


考虑处理特定任务的键的方法。


“任务”


想象一下,在现有项目中,您需要实现键盘输入处理。 同时,当然,纯粹出于历史原因,项目接口及其控制器也是如此。 并且有以下内容:


ParentController ,其中有两个组件,分别是其状态和状态。 Controller1和使用CTRL+SHIFT+F来搜索站点的元素,以及Controller2及其DOM元素(这是一个本地区域),在其中进行搜索。 但是,它们可以同时显示在屏幕上。 以下是解决此问题的几种方法。


1.“ KeyboardEvent及其手动处理”


KeyboardEvent对象描述用户如何与键盘交互。 每个事件都由一个键描述。 事件的类型(按键,击键或击键)确定所产生操作的类型。


听起来不错吧? 让我们仔细看看。
考虑CTRL+SHIFT+F键拦截,通常对应于全局搜索调用。


 element.addEventListener('keypress', (event) => { const keyName = event.key; //        // ..     SHIFT      if (event.ctrlKey && event.shiftKey && event.key.toLowerCase() === 't') { alert('CTRL+SHIFT+T pressed'); } }); 

现在,适用于我们的任务,您可以执行两种方式(例如)


分别执行控制器1和2中的按键拦截


这将导致以下事实:根据DOM中的顺序,您可能需要useCapture来保证Controller2和Controller1的处理将具有useCapture 。 因此,您将获得隔离的逻辑,但是如果应用程序很复杂并且有很多这样的控制器,那么此解决方案就不好了,因为 有些可以同时显示在屏幕上,并且它们可以具有自己严格的处理顺序,这不取决于它们在DOM树中的位置。 (请参阅冒泡和捕获


CommonController键捕获


一种替代解决方案是在公共父控制器中处理单击,该父控制器确切知道何时显示其子级,由第一和第二控制器控制。 在增加子控制器的同时,这不会导致捕获事件和确定处理哪个键的控制器方面的困难。 但是,将存在另一个问题- if在父控制器中出现粗线, if该粗线将处理所有可能的情况。 对于大型应用程序,此解决方案不合适,因为 在某个时候,可能会出现另一个不是ParentController的子级的Controller ParentController那么您将不得不ParentController处理程序上ParentController一个级别到其公共父级,依此类推...直到迟早一个控制器开始对其中的元素了解得太多。



实际上,只有80%的浏览器可以使用KeboardEvent.key ,其余所有您都需要操作KeboardEvent.keyCode :带有键控代码的数字。 这极大地使生活复杂化。 这里值得对这种方法的缺点进行描述。


缺点:


  • 代码的组织不是很方便,它需要一张字符代码卡及其等效的文本,以及其他减少处理程序中代码量的实用程序。
  • 浏览器80%的支持仅使用符号而不使用它们的代码仍然不够。
  • 使用useCapture一个处理程序重叠到另一个处理程序。
  • 如果存在具有useCapture钩子和具有相同处理程序的嵌套元素
    调试很困难。
  • 可伸缩性差。

但是从本质上讲,没有不必要的依赖项和库


接下来,我们将讨论两个库,其中一个库旨在解决它们自己的类似问题。


2.“使用热键库”


github上有三千个星星,大小适中,没有依赖关系。 一家中国制造商向我们承诺将提供适合所有人的解决方案。 但是,我们不要着急。 让我们尝试在其帮助下解决我们的问题。


 //   hotkeys('ctrl+shift+f', function(event, handler){ alert('CTRL+SHIFT+T pressed'); }); 

语法看起来已经很短了,解决该问题的主要芯片将是直接在屏幕上显示控制器1和2的组件。 在库代码中翻了几番之后,很容易注意到处理程序会形成一个堆栈,这些堆栈会在注册时又出现在屏幕上而被填充或清除(比方说,出现在处理程序中的元素晚于现有处理程序的元素将在处理热键的队列中具有优先级)。


经常发生应拦截处理的元素稍后出现。 在这种情况下,我们可以安全地将点击处理的逻辑传播到每个控制器。 示波器等其他芯片将帮助我们将点击的来源与另一点击分开。 但是,如果则会出现与本机eventListener相同的问题。 我们必须将所有内容放入一个公共的父控制器中。


此外,经常会发生这样的情况,您需要阻止默认行为,但同时不会将事件视为已处理(换句话说,如果我们接收到事件,是否对该事件进行了处理就没有明确的了解),或者必须同时由两个控制器对其进行处理。 其中一个将引起对行为的反应,而另一个将仅考虑该事件是。


总加分:


  • 范围使您可以分隔流。
  • 语法清晰明了。
  • 顺序确定元素的外观,而不是DOM中的位置。
  • 大小和缺乏依赖性。

缺点:


  • 一次只能处理一个范围
  • 由于循环中的函数调用,调试仍然很困难,可能不知道在哪个处理程序上进行调试 迷路了 事件处理
  • 如果事件具有defaultPrevented标志并且其分发被中断,则处理该事件的语句不正确。
  • 呼叫注册和事件退订的全局功能

它适合解决典型的任务,但是编写交易终端或大型管理面板会出现问题,以确保进行调试。


3.“使用堆栈快捷方式库”


由于进行了多次抽佣和尝试使用其他人的解决方案,我不得不 自行车 首先,该库将有助于正常亮相,保留流行库的所有最佳属性并带来新的东西。


创建时解决了哪些任务?


  • 无功操作原理
  • 简单的调试处理程序
  • 明确的事件处理状态
  • 跨平台
  • 进口便利,缺乏全球职能
  • 连接时无直接窗口访问
  • 无需调用preventDefaultstopPropagation

 //  this.shortcuts = shortcuts({ 'CMD+SHIFT+F': function (event, next) { alert('CMD+SHIFT+F pressed'); } }); //  this.shortcuts.destroy(); 

适用于我们的任务的解决方案与以前的库完全一致。 在没有太多彼此了解的情况下,处理逻辑的完全分离仍然没有发生,但是很多事情变得更加简单和易于理解。 由于以下原因:


  • 仍然没有绑定到DOM(一个侦听器除外),并且根据处理程序的注册顺序填充了处理程序堆栈。
  • scope立即拒绝使用scope进行隔离。 目前尚不清楚它能解决什么任务,而且似乎只会使架构复杂化。
  • 调试和有关它的下一个功能可能值得更多...
  • 他在event.detail携带的数据的事件中发生了突变。

调试处理程序的安排方式是,在callstack之前由它们形成一个callstack栈。 它允许您在控制台中查看从第一个处理程序到下一个处理程序的整个事件链。


next() -函数调用意味着该事件尚未处理,将被传递给下一个处理程序。 一种非常熟悉的合同,适用于express中间处理程序或中间件。 因此,您将始终知道事件是否已处理,是否刚刚被突变或“考虑在内”。



如果您在其中之一中设置了断点,这就是调用堆栈的外观。


好吧,关于缺点:


  • 尚无打字稿打字稿。
  • 无范围-无法创建分屏网站)
  • 注册期间的一种组合(这不是CMD+F,CMD+V,T不会理解逗号)

Source: https://habr.com/ru/post/zh-CN438770/


All Articles