我想我应该使用指令,但是将指令添加到主体似乎很奇怪,但是侦听文档中的事件。
什么是正确的方法?
$document.bind('keypress')
参见$ document
Answers:
这就是我使用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>
我会说一种更合适的方法(或“ Angular方法”)是将其添加到指令中。这是一个简单的方法(只需将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>'
};
}
]);
Escape
密钥?
用途$document.bind
:
function FooCtrl($scope, $document) {
...
$document.bind("keypress", function(event) {
console.debug(event)
});
...
}
$event
函数将其传递给控制器,另一种是将事件直接绑定到控制器中。控制器方法似乎更少的代码,并且结果相同。是否有理由选择一种方法而不是另一种方法?
var that = this; $document.bind("keydown", function(event) { $scope.$apply(function(){ that.handleKeyDown(event); });
我还不能保证,但是我开始看一下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);
这是一个用于键盘快捷键的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文档代码中完成的方法,即按/
开始搜索。
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=预览
作为服务
将该指令转换为服务非常容易。唯一的真正区别是范围未在服务上公开。要触发摘要,您可以输入$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版本
稍短的答案只是看下面的解决方案3。如果您想了解更多选择,可以阅读全文。
我同意jmagnusson。但是我相信有更清洁的解决方案。不用将键与指令中的函数绑定,您应该能够像定义配置文件一样将它们与html绑定,并且热键应与上下文相关。
以下是使用带有自定义指令的鼠标陷阱的版本。(我不是这个小提琴的作者。)
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>
该解决方案要求您包括mousetrap.js,这是可帮助您定义热键的库。
如果您想避免开发自己的自定义指令的麻烦,可以签出以下库:
https://github.com/drahak/angular-hotkeys
还有这个
https://github.com/chieffancypants/angular-hotkeys
第二个提供了更多的功能和灵活性,即为您的应用程序自动生成的热键备忘单。
更新:Angular ui不再提供解决方案3。
除了上述解决方案之外,angularui团队还完成了另一项实现。但是缺点是解决方案取决于JQuery lib,这不是angular社区的趋势。(Angular社区尝试仅使用angularjs附带的jqLite来摆脱过度使用的依赖项。)这是链接
用法是这样的:
在您的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,它避免了我遇到的许多小怪问题。
我提供了快捷方式服务。
看起来像:
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注入到控制器中。
这是错误的控制器做法,并且违反了“控制器中永远不要访问$ 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);
}
})
}
}
})
好多了
下面,让您在控制器中编写所有快捷方式逻辑,该指令将负责其他所有事项。
指示
.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>