Javascript AngularJS创建全局键盘快捷键的方法是什么?

Javascript AngularJS创建全局键盘快捷键的方法是什么?,javascript,angularjs,Javascript,Angularjs,我想我应该使用指令,但将指令添加到正文中,但侦听文档上的事件似乎很奇怪 这样做的正确方法是什么 更新:找到AngularJS UI并看到了keypress指令的实现。以下是我如何使用jQuery实现的-我认为有更好的方法 var app = angular.module('angularjs-starter', []); app.directive('shortcut', function() { return { restrict: 'E', replace: true,

我想我应该使用指令,但将指令添加到正文中,但侦听文档上的事件似乎很奇怪

这样做的正确方法是什么


更新:找到AngularJS UI并看到了keypress指令的实现。

以下是我如何使用jQuery实现的-我认为有更好的方法

var app = angular.module('angularjs-starter', []);

app.directive('shortcut', function() {
  return {
    restrict: 'E',
    replace: true,
    scope: true,
    link:    function postLink(scope, iElement, iAttrs){
      jQuery(document).on('keypress', function(e){
         scope.$apply(scope.keyPressed(e));
       });
    }
  };
});

app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';
  $scope.keyCode = "";
  $scope.keyPressed = function(e) {
    $scope.keyCode = e.which;
  };
});

按查看键
{{keyCode}}

使用
$document.bind

function FooCtrl($scope, $document) {
    ...
    $document.bind("keypress", function(event) {
        console.debug(event)
    });
    ...
}

我想说一种更合适的方式(或“角度方式”)是将其添加到指令中。下面是一个简单的方法(只需将
keypress events
属性添加到
):

在您的指令中,您可以简单地执行以下操作:

module.directive('myDirective', [
  function() {
    return {
      restrict: 'E',
      link: function(scope, el, attrs) {
        scope.keyPressed = 'no press :(';
        // For listening to a keypress event with a specific code
        scope.$on('keypress:13', function(onEvent, keypressEvent) {
          scope.keyPressed = 'Enter';
        });
        // For listening to all keypress events
        scope.$on('keypress', function(onEvent, keypressEvent) {
          if (keypress.which === 120) {
            scope.keyPressed = 'x';
          }
          else {
            scope.keyPressed = 'Keycode: ' + keypressEvent.which;
          }
        });
      },
      template: '<h1>{{keyPressed}}</h1>'
    };
  }
]);
function MyController($scope, $timeout, keyboardManager) {
    // Bind ctrl+shift+d
    keyboardManager.bind('ctrl+shift+d', function() {
        console.log('Callback ctrl+shift+d');
    });
}
module.directive('myDirective'[
函数(){
返回{
限制:'E',
链接:功能(范围、el、属性){
scope.keyPressed='不按:(';
//用于收听带有特定代码的按键事件
作用域:$on('keypress:13',功能(OneEvent,keypressEvent){
scope.keyPressed='Enter';
});
//用于收听所有按键事件
作用域:$on('keypress',功能(OneEvent,keypressEvent){
if(按键,哪个===120){
scope.keyPressed='x';
}
否则{
scope.keyPressed='Keycode:'+keypressEvent.which;
}
});
},
模板:“{keyPressed}}”
};
}
]);

以下是键盘快捷键AngularJS服务的示例:

然后可以这样使用它:

module.directive('myDirective', [
  function() {
    return {
      restrict: 'E',
      link: function(scope, el, attrs) {
        scope.keyPressed = 'no press :(';
        // For listening to a keypress event with a specific code
        scope.$on('keypress:13', function(onEvent, keypressEvent) {
          scope.keyPressed = 'Enter';
        });
        // For listening to all keypress events
        scope.$on('keypress', function(onEvent, keypressEvent) {
          if (keypress.which === 120) {
            scope.keyPressed = 'x';
          }
          else {
            scope.keyPressed = 'Keycode: ' + keypressEvent.which;
          }
        });
      },
      template: '<h1>{{keyPressed}}</h1>'
    };
  }
]);
function MyController($scope, $timeout, keyboardManager) {
    // Bind ctrl+shift+d
    keyboardManager.bind('ctrl+shift+d', function() {
        console.log('Callback ctrl+shift+d');
    });
}

更新:我现在改用。

我为快捷方式提供了服务

它看起来像:

angular.module('myApp.services.shortcuts', [])
  .factory('Shortcuts', function($rootScope) {
     var service = {};
     service.trigger = function(keycode, items, element) {
       // write the shortcuts logic here...
     }

     return service;
})
我把它注入控制器:

angular.module('myApp.controllers.mainCtrl', [])
  .controller('mainCtrl', function($scope, $element, $document, Shortcuts) {
   // whatever blah blah

   $document.on('keydown', function(){
     // skip if it focused in input tag  
     if(event.target.tagName !== "INPUT") {
        Shortcuts.trigger(event.which, $scope.items, $element);
     }
   })
})
hotkeys.add('n', 'Create a new Category', $scope.showCreateView);
hotkeys.add('e', 'Edit the selected Category', $scope.showEditView);
hotkeys.add('d', 'Delete the selected Category', $scope.remove);
它可以工作,但您可能会注意到我将$element和$document注入控制器

这是一种糟糕的控制器实践,违反了“永远不要访问控制器中的$element”约定

我应该把它放到指令中,然后使用'ngKeydown'和$event来触发服务

但我认为服务很好,我会尽快重做控制器


更新:

似乎“ng keydown”只在输入标记中起作用

因此,我只需编写一个指令并注入$document:

angular.module('myApp.controllers.mainCtrl', [])
  .directive('keyboard', function($scope, $document, Shortcuts) {
   // whatever blah blah
   return {
     link: function(scope, element, attrs) {
       scope.items = ....;// something not important

       $document.on('keydown', function(){
         // skip if it focused in input tag  
         if(event.target.tagName !== "INPUT") {
           Shortcuts.trigger(event.which, scope.items, element);
         }
       })
     }
   }
  })

更好。

我现在还不能保证,但我已经开始查看AngularHotkeys.js:

一旦我下定决心,我会更新更多信息

更新1:哦,有一个nuget软件包:角度热键

更新2:实际上非常容易使用,只需在路线中或在控制器中设置绑定:

angular.module('myApp.controllers.mainCtrl', [])
  .controller('mainCtrl', function($scope, $element, $document, Shortcuts) {
   // whatever blah blah

   $document.on('keydown', function(){
     // skip if it focused in input tag  
     if(event.target.tagName !== "INPUT") {
        Shortcuts.trigger(event.which, $scope.items, $element);
     }
   })
})
hotkeys.add('n', 'Create a new Category', $scope.showCreateView);
hotkeys.add('e', 'Edit the selected Category', $scope.showEditView);
hotkeys.add('d', 'Delete the selected Category', $scope.remove);

略短一点的答案是看下面的解决方案3。如果你想知道更多选项,你可以阅读全文

我同意jmagnusson。但我相信有更干净的解决方案。与其在指令中绑定键和函数,不如像定义配置文件一样在html中绑定它们,热键应该是上下文的

  • 下面是一个使用自定义指令的鼠标陷阱的版本 不是这把小提琴的作者。)

    您将需要包括mousetrap.js,并按如下方式使用它:

    <div ng-app="keyExample">
        <div ng-controller="RootController">
            <keybinding on="g i" invoke="gotoInbox()" />
            <div ng-controller="ChildController">
                <keybinding on="g l" invoke="gotoLabel('Sent')" />
            </div>
        </div>
        <div>Click in here to gain focus and then try the following key strokes</div>
        <ul>
            <li>"g i" to show a "Goto Inbox" alert</li>
            <li>"g l" to show a "Goto Label" alert</li>
        </ul>
    </div>
    

    在使用了所有的解决方案之后,我推荐Angular UI团队实现的解决方案,解决方案3避免了我遇到的许多奇怪的小问题。

    从guys behid ng-newsletter.com查看这一点;查看创建2048游戏,它有一些很好的代码,使用键盘事件服务。

    作为指示

    .directive('shortcuts', ['$document', '$rootScope', function($document, $rootScope) {
        $rootScope.shortcuts = [];
    
        $document.on('keydown', function(e) {
            // Skip if it focused in input tag.
            if (event.target.tagName !== "INPUT") {
                $rootScope.shortcuts.forEach(function(eventHandler) {
                    // Skip if it focused in input tag.
                    if (event.target.tagName !== 'INPUT' && eventHandler)
                        eventHandler(e.originalEvent, e)
                });
            }
        })
    
        return {
            restrict: 'A',
            scope: {
                'shortcuts': '&'
            },
            link: function(scope, element, attrs) {
                $rootScope.shortcuts.push(scope.shortcuts());
            }
        };
    }])
    
    这基本上是在Angular documentation代码中完成的,即按
    /
    开始搜索

    angular
     .module("app", [])
     .directive("keyboard", keyboard);
    
    function keyboard($document) {
    
      return {
        link: function(scope, element, attrs) {
    
          $document.on("keydown", function(event) {
    
          // if keycode...
          event.stopPropagation();
          event.preventDefault();
    
          scope.$apply(function() {            
            // update scope...          
          });
        }
      };
    }
    
    使用键盘指令的Plunk


    作为一项服务

    .directive('shortcuts', ['$document', '$rootScope', function($document, $rootScope) {
        $rootScope.shortcuts = [];
    
        $document.on('keydown', function(e) {
            // Skip if it focused in input tag.
            if (event.target.tagName !== "INPUT") {
                $rootScope.shortcuts.forEach(function(eventHandler) {
                    // Skip if it focused in input tag.
                    if (event.target.tagName !== 'INPUT' && eventHandler)
                        eventHandler(e.originalEvent, e)
                });
            }
        })
    
        return {
            restrict: 'A',
            scope: {
                'shortcuts': '&'
            },
            link: function(scope, element, attrs) {
                $rootScope.shortcuts.push(scope.shortcuts());
            }
        };
    }])
    
    将该指令转换为服务非常容易。唯一真正的区别是作用域未在服务上公开。要触发摘要,可以引入
    $rootScope
    或使用
    $timeout

    function Keyboard($document, $timeout, keyCodes) {
      var _this = this;
      this.keyHandlers = {};
    
      $document.on("keydown", function(event) {        
        var keyDown = _this.keyHandlers[event.keyCode];        
        if (keyDown) {
          event.preventDefault();
          $timeout(function() { 
            keyDown.callback(); 
          });          
        }
      });
    
      this.on = function(keyName, callback) {
        var keyCode = keyCodes[keyName];
        this.keyHandlers[keyCode] = { callback: callback };
        return this;
      };
    }
    
    现在,您可以使用
    keyboard.on()
    方法在控制器中注册回调

    function MainController(keyboard) {
    
      keyboard
        .on("ENTER",  function() { // do something... })
        .on("DELETE", function() { // do something... })
        .on("SHIFT",  function() { // do something... })
        .on("INSERT", function() { // do something... });       
    }
    
    使用服务的Plunk的替代版本


    下面让我们将所有快捷方式逻辑写入控制器,指令将处理所有其他内容

    指令

    .directive('shortcuts', ['$document', '$rootScope', function($document, $rootScope) {
        $rootScope.shortcuts = [];
    
        $document.on('keydown', function(e) {
            // Skip if it focused in input tag.
            if (event.target.tagName !== "INPUT") {
                $rootScope.shortcuts.forEach(function(eventHandler) {
                    // Skip if it focused in input tag.
                    if (event.target.tagName !== 'INPUT' && eventHandler)
                        eventHandler(e.originalEvent, e)
                });
            }
        })
    
        return {
            restrict: 'A',
            scope: {
                'shortcuts': '&'
            },
            link: function(scope, element, attrs) {
                $rootScope.shortcuts.push(scope.shortcuts());
            }
        };
    }])
    
    控制器

        $scope.keyUp = function(key) {
            // H.
            if (72 == key.keyCode)
                $scope.toggleHelp();
        };
    
    Html

    <div shortcuts="keyUp">
        <!-- Stuff -->
    </div>
    

    你可以试试这个库。它使管理热键变得非常容易,在你浏览应用程序时,它会自动绑定和解除绑定键


    我不知道这是否是一种真正的角度方式,但我做了什么

    $(document).on('keydown', function(e) {
        $('.button[data-key=' + String.fromCharCode(e.which) + ']').click();
    });
    
    <div class="button" data-key="1" ng-click="clickHandler($event)">
        ButtonLabel         
    </div>
    
    $(文档).on('keydown',函数(e){
    $('.button[data key='+String.fromCharCode(e.which)+']')。单击();
    });
    纽扣标签
    
    我想你指的是键盘快捷键……我对此也很好奇,我得出的结论是angular并不是执行此任务的最佳工具。我写了一个指令来实现这一点,但存在一些问题——首先是你提到的语义问题,而且我认为在指令中封装jquery被认为不是一个好的做法,当有多个模板时,这导致了一些混乱的情况,其中只有一些模板需要文档快捷方式。快捷方式需要与我的控制器连接。我看不到外部jquery模块的任何好处。我也看到了两种可能的方式:1)jquery外部快捷方式模块+与控制器的pubsub通信。2) angularjs指令,这很奇怪,但我认为提供带有快捷方式的链接函数是可以的。我不认为您可以将angularjs ui指令添加到文档中,它们的作用域是一个元素。不需要额外的库。。。使用
    $document.bind('keypress')
    查看链接现在是404。如果有更新的位置,请更新。谢谢回复。我知道你认为我们应该按照指令来做。link:functionpostlink(scope,iElement,iAttrs){wi