Как AngularJS способ создания глобальных сочетаний клавиш?

Я полагаю, что я должен использовать директиву, но кажется странным добавлять директиву в тело, но слушать события в документе.

Как правильно это сделать?

ОБНОВЛЕНИЕ: нашел пользовательский интерфейс AngularJS и увидел их реализацию директивы нажатия клавиш.

73 голоса | спросил ValeriiVasin 23 FebruaryEurope/MoscowbSat, 23 Feb 2013 23:13:23 +0400000000pmSat, 23 Feb 2013 23:13:23 +040013 2013, 23:13:23

10 ответов


0

Вот как я это сделал с помощью 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;
  };
});
<body ng-controller="MainCtrl">
  <shortcut></shortcut>
  <h1>View keys pressed</h1>
  {{keyCode}}
</body>

Демо-версия Plunker

ответил Jason 23 FebruaryEurope/MoscowbSat, 23 Feb 2013 23:58:38 +0400000000pmSat, 23 Feb 2013 23:58:38 +040013 2013, 23:58:38
0

Я бы сказал, что более правильным способом (или «угловым путем») было бы добавить его в директиву. Вот простой способ начать работу (просто добавьте атрибут keypress-events в <body>):

angular.module('myDirectives', []).directive('keypressEvents', [
  '$document',
  '$rootScope',
  function($document, $rootScope) {
    return {
      restrict: 'A',
      link: function() {
        $document.bind('keypress', function(e) {
          console.log('Got keypress:', e.which);
          $rootScope.$broadcast('keypress', e);
          $rootScope.$broadcast('keypress:' + e.which, e);
        });
      }
    };
  }
]);

В вашей директиве вы можете просто сделать что-то вроде этого:

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>'
    };
  }
]);
ответил jmagnusson 16 +04002013-10-16T23:33:46+04:00312013bEurope/MoscowWed, 16 Oct 2013 23:33:46 +0400 2013, 23:33:46
0

Я пока не могу ручаться за это, но я начал смотреть на AngularHotkeys.js:

http://chieffancypants.github.io/angular-hotkeys/

Обновлюсь с дополнительной информацией, как только у меня появятся зубы.

Обновление 1: есть пакет nuget: angular-hotkeys

Обновление 2: на самом деле очень прост в использовании, просто настройте привязку либо на своем маршруте, либо, как я, на вашем контроллере:

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);
ответил A. Murray 22 PMpTue, 22 Apr 2014 15:10:38 +040010Tuesday 2014, 15:10:38
0

Вот пример службы AngularJS для сочетаний клавиш: http://jsfiddle.net/firehist/nzUBg/

Затем его можно использовать так:

function MyController($scope, $timeout, keyboardManager) {
    // Bind ctrl+shift+d
    keyboardManager.bind('ctrl+shift+d', function() {
        console.log('Callback ctrl+shift+d');
    });
}

Обновление . Вместо этого я использую angular-hotkeys .

ответил Tom Söderlund 6 32013vEurope/Moscow11bEurope/MoscowWed, 06 Nov 2013 16:22:32 +0400 2013, 16:22:32
0

В качестве директивы

По сути, это то, как это делается в коде документации Angular, т. е. нажмите /, чтобы начать поиск.

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...          
      });
    }
  };
}

Вставьте, используя директиву клавиатуры

http://plnkr.co/edit/C61Gnn?p=preview


Как услуга

Преобразовать эту директиву в сервис очень просто. Единственное реальное различие заключается в том, что область действия не отображается на службе. Чтобы вызвать дайджест, вы можете ввести $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 с использованием службы

http://plnkr.co/edit/z9edu5?p=preview

ответил Blake Bowen 14 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowSun, 14 Sep 2014 15:09:33 +0400 2014, 15:09:33
0

Немного более короткий ответ - просто посмотрите на решение 3 ниже. Если вы хотите узнать больше вариантов, вы можете прочитать все это.

Я согласен с Jmagnusson. Но я верю, что есть более чистое решение. Вместо того, чтобы связывать ключи с функциями в директиве, вы должны просто связать их в html, как определение файла конфигурации, и горячие клавиши должны быть контекстными.

  1. Ниже приведена версия, в которой используется ловушка мыши с пользовательской директивой. (Я не был автором этой скрипки.)

    var app = angular.module('keyExample', []);
    
    app.directive('keybinding', function () {
        return {
            restrict: 'E',
            scope: {
                invoke: '&'
            },
            link: function (scope, el, attr) {
                Mousetrap.bind(attr.on, scope.invoke);
            }
        };
    });
    
    app.controller('RootController', function ($scope) {
        $scope.gotoInbox = function () {
            alert('Goto Inbox');
        };
    });
    
    app.controller('ChildController', function ($scope) {
        $scope.gotoLabel = function (label) {
            alert('Goto Label: ' + label);
        };
    });
    

    Вам нужно будет включить 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>
    

    http://jsfiddle.net/BM2gG/3/

    Решение требует, чтобы вы включили mousetrap.js, который является библиотекой которые помогут вам определить горячие клавиши.

  2. Если вы хотите избежать трудностей, чтобы разработать свой собственный директива, вы можете проверить эту библиотеку:

    https://github.com/drahak/angular-hotkeys

    И это

    https://github.com/chieffancypants/angular-hotkeys

    Второй обеспечивает немного больше возможностей и гибкости, т.е. автоматически сгенерированный шпаргалка для вашего приложения.

Обновление : решение 3 больше не доступно в Angular ui.

  1. Помимо приведенных выше решений, есть еще одна реализация командой angularui. Но недостатком является то, что решение зависит от JQuery lib, которая не является тенденцией в ангулярном сообществе (Угловая сообщество пытается просто использовать jqLite, который поставляется с angularjs и уйти от переутомленных зависимостей.) Вот ссылка

    http://angular-ui.github.io/ui-utils/# /нажатие клавиши

Использование выглядит следующим образом:

В своем html используйте атрибут ui-keydown для привязки клавиш и функций.

<div class="modal-inner" ui-keydown="{
                        esc: 'cancelModal()',
                        tab: 'tabWatch($event)',
                        enter: 'initOrSetModel()'
                    }">

В вашей директиве добавьте эти функции в свою область.

app.directive('yourDirective', function () {
   return {
     restrict: 'E',
     templateUrl: 'your-html-template-address.html'
     link: function(){
        scope.cancelModal() = function (){
           console.log('cancel modal');
        }; 
        scope.tabWatch() = function (){
           console.log('tabWatch');
        };
        scope.initOrSetModel() = function (){
           console.log('init or set model');
        };
     }
   };
});

Изучив все решения, я бы порекомендовал решение, реализованное командой Angular UI, решение 3, которое позволило избежать многих мелких странных проблем, с которыми я столкнулся.

ответил Tim Hong 7 Mayam14 2014, 07:14:33
0

Я сделал сервис для ярлыков.

Это выглядит так:

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);
     }
   })
})

Это работает, но вы можете заметить, что я вставляю $ element и $ document в контроллер.

Это плохая практика работы с контроллером, и она нарушает соглашение 'Dont EVER access $ element in the controller'.

Я должен поместить это в директиву, затем использовать '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);
         }
       })
     }
   }
  })

Это лучше.

ответил zisasign 18 Jpm1000000pmSat, 18 Jan 2014 12:24:10 +040014 2014, 12:24:10
0

Следующее позволяет вам записать всю вашу логику ярлыков в контроллере, а директива позаботится обо всем остальном.

Директива

.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>
ответил Reimund 24 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 24 Sep 2015 17:17:13 +0300 2015, 17:17:13
0

вы можете попробовать эту библиотеку, благодаря которой стало очень легко управлять горячими клавишами, она автоматически связывает и отменяет привязку клавиш при перемещении по приложению

угловые горячие клавиши

ответил Ahmed Ahmed 1 +03002015-10-01T19:02:42+03:00312015bEurope/MoscowThu, 01 Oct 2015 19:02:42 +0300 2015, 19:02:42
0

я не знаю, настоящий ли это угловой, но что я сделал

$(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>
ответил wutzebaer 1 MaramTue, 01 Mar 2016 02:08:13 +03002016-03-01T02:08:13+03:0002 2016, 02:08:13

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132