Javascript 使用ES6类作为Angular 1.x指令
我正在做一个小项目来研究ES6带来的好东西,我试图将register类设置为angular指令,但我遇到了一个错误“TypeError:无法将类作为函数调用”,但从示例中我发现他们只是编写类并将其注册为angular指令。这是我的指令Javascript 使用ES6类作为Angular 1.x指令,javascript,angularjs,class,angularjs-directive,ecmascript-6,Javascript,Angularjs,Class,Angularjs Directive,Ecmascript 6,我正在做一个小项目来研究ES6带来的好东西,我试图将register类设置为angular指令,但我遇到了一个错误“TypeError:无法将类作为函数调用”,但从示例中我发现他们只是编写类并将其注册为angular指令。这是我的指令 class dateBlock { constructor () { this.template = '/app/dateblock/dateblock.html'; this.restrict = 'AE'; this.scope =
class dateBlock {
constructor () {
this.template = '/app/dateblock/dateblock.html';
this.restrict = 'AE';
this.scope = {};
}
};
export default dateBlock
以及我的索引,我在其中导入它,然后声明它
import calendarController from './calendar/calendar.js'
import dateBlock from './dateblock/dateblock.js'
function setup($stateProvider) {
$stateProvider
.state('base', {
url: '',
controller: calendarController,
templateUrl: '/app/calendar/calendar.html'
});
};
setup.$inject = ['$stateProvider']
var app = angular.module('calApp',['ngAnimate','ui.router','hmTouchEvents', 'templates'])
.config(setup)
.controller('calendarController', calendarController)
.directive('dateBlock', dateBlock)
如果我错过了关键的一步,我很想听到。另外一个附带问题是,将所有应用程序组件导入索引并在那里注册,还是导出应用程序并在组件中导入并注册?我遇到了类似的问题。但在我的例子中,当我部署到生产环境时,它成功了,但失败了。但它失败了,因为生产中使用了最新版本的6to5。 这可以通过使用
npm shrinkwrap
来防止。
根据最新的ES6规范,您不能使用这样的类 如注释中所述,
module.directive()
方法需要工厂函数而不是构造函数
最简单的方法是将类包装在返回实例的函数中:
angular.module('app')
.directive('dateBlock', () => new DateBlock());
但是,这只在最有限的意义上起作用-它不允许依赖项注入,并且指令的编译
和链接
功能(如果已定义)将无法按预期工作
事实上,这是一个我已经深入研究过的问题,结果证明解决起来相当棘手(至少对我来说)
我写了一篇内容广泛的文章,介绍了我的解决方案,但就您而言,我可以向您指出需要解决的两个主要问题:
我认为,完整的解决方案需要太多的代码才能粘贴到这里,但我已经准备了一个工作演示项目,它允许您将指令定义为ES6类,如下所示:
class MyDirective {
/*@ngInject*/
constructor($interval) {
this.template = '<div>I\'m a directive!</div>';
this.restrict = 'E';
this.scope = {}
// etc. for the usual config options
// allows us to use the injected dependencies
// elsewhere in the directive (e.g. compile or link function)
this.$interval = $interval;
}
// optional compile function
compile(tElement) {
tElement.css('position', 'absolute');
}
// optional link function
link(scope, element) {
this.$interval(() => this.move(element), 1000);
}
move(element) {
element.css('left', (Math.random() * 500) + 'px');
element.css('top', (Math.random() * 500) + 'px');
}
}
// `register` is a helper method that hides all the complex magic that is needed to make this work.
register('app').directive('myDirective', MyDirective);
class-MyDirective{
/*@Nginect*/
构造函数($interval){
this.template='I'm a directive!';
this.restrict='E';
this.scope={}
//等,以获取常用的配置选项
//允许我们使用注入的依赖项
//指令中的其他地方(例如编译或链接函数)
这个.$interval=$interval;
}
//可选编译函数
编辑(远程通讯){
css(‘位置’、‘绝对’);
}
//可选链接功能
链接(范围、元素){
this.$interval(()=>this.move(元素),1000);
}
移动(元素){
css('left',(Math.random()*500)+'px');
css('top',(Math.random()*500)+'px');
}
}
//register是一个helper方法,它隐藏了实现此功能所需的所有复杂魔法。
寄存器('app')。指令('myDirective',myDirective);
检查一下,迈克尔的钱就在上面: directive()方法需要一个工厂函数 然而我用另一种技术解决了它,我想稍微干净一点,它对我来说很好,但并不完美。。。 我定义了一个静态方法,该方法返回模块()所期望的工厂 在我的应用程序中,我会:
angular.module('vineyard',[]).directive('vineScroller', VineDirective.directiveFactory)
我相信没有其他方法可以使用类+指令,在这一点上,只需选择简单的一种;-) 我也面临同样的问题。我第一次尝试通过ES6类解决这个问题,但我的依赖项有问题。在我意识到有两种编写代码的风格之后,我尝试了。总之,我使用了样式,并在我的rails应用程序ES6中获得了以下works代码:
((angular) => {
'use strict';
var Flash = ($timeout) => {
return {
restrict: 'E',
scope: {
messages: '=messages'
},
template: (() => {
return "<div class='alert flash-{{ message[0] }}' ng-repeat = 'message in messages'>" +
"<div class= 'close' ng-click = 'closeMessage($index)' data-dismiss = 'alert' > × </div>" +
"<span class= 'message' >{{ message[1] }}</ span>" +
"</ div>";
}),
link: (scope) => {
scope.closeMessage = (index) => {
scope.messages.splice(index, 1)
};
$timeout(() => {
scope.messages = []
}, 5000);
}
}
};
Flash.$inject = ['$timeout'];
angular.module('Application').directive('ngFlash', Flash);
})(window.angular);
((角度)=>{
"严格使用",;
var Flash=($timeout)=>{
返回{
限制:'E',
范围:{
消息:'=消息'
},
模板:(()=>{
返回“”+
" × " +
“{{消息[1]}”+
"";
}),
链接:(范围)=>{
scope.closeMessage=(索引)=>{
作用域消息拼接(索引,1)
};
$timeout(()=>{
scope.messages=[]
}, 5000);
}
}
};
Flash.$inject=['$timeout'];
角度。模块(“应用”)。指令(“ngFlash”,Flash);
})(窗口角度);
我知道我可以用ES6风格的函数和变量做一些改进。
我希望有帮助 在我看来,没有必要使用register.js这样的外部库,因为您可以通过以下方式将指令创建为ES6类:
class MessagesDirective {
constructor() {
this.restrict = 'E'
this.templateUrl = 'messages.html'
this.scope = {}
}
controller($scope, $state, MessagesService) {
$scope.state = $state;
$scope.service = MessagesService;
}
link(scope, element, attrs) {
console.log('state', scope.state)
console.log('service', scope.service)
}
}
angular.module('messages').directive('messagesWidget', () => new MessagesDirective)
使用指令控制器允许您插入依赖项,即使没有其他声明(例如,
MessagesDirective.$inject=['$scope'、'$state'、'MessagesService']
),所以如果需要,您可以通过作用域在链接函数中使用服务 一个更简单、更干净、更易读的解决方案在我的项目中,我使用了一种语法sugar进行注射。ES6使指令使用可注入工厂变得非常简单,避免了太多重复代码。这段代码允许注入继承,使用带注释的注入等等。选中此项:
第一步
为所有angular Controller\Directions\services-InjectableClient声明基类其主要任务-将所有注入的参数设置为“this”的属性。可以覆盖此行为,请参见下面的示例
class InjectionClient {
constructor(...injected) {
/* As we can append injections in descendants we have to process only injections passed directly to current constructor */
var injectLength = this.constructor.$inject.length;
var injectedLength = injected.length;
var startIndex = injectLength - injectedLength;
for (var i = startIndex; i < injectLength; i++) {
var injectName = this.constructor.$inject[i];
var inject = injected[i - startIndex];
this[injectName] = inject;
}
}
static inject(...injected) {
if (!this.$inject) {
this.$inject = injected;
} else {
this.$inject = injected.concat(this.$inject);
}
};
}
第三步
现在我们可以声明尽可能多的指令类。有继承权。我们可以用扩展数组简单地设置注入(只是别忘了调用超级方法)。见示例:
class DirectiveFirst extends Directive {
}
DirectiveFirst.inject('injA', 'injB', 'injC');
class DirectiveSecond extends DirectiveFirst {
constructor(injD, ...injected) {
super(...injected);
this.otherInjectedProperty = injD;
}
}
// See appended injection does not hurt the ancestor class
DirectiveSecond.inject('injD');
class DirectiveThird extends DirectiveSecond {
constructor(...injected) {
// Do not forget call the super method in overridden constructors
super(...injected);
}
}
最后一步
现在,以简单的方式向angular注册指令:
angular.directive('directiveFirst', DirectiveFirst.factory());
angular.directive('directiveSecond', DirectiveSecond.factory());
angular.directive('directiveThird', DirectiveThird.factory());
export default function archiveTreeDirective() {
'ngInject';
return {
restrict: 'E',
scope: {
selectedNodes: "="
},
templateUrl: 'app/components/directives/archiveTree/archiveTree.html',
controller: ArchiveTreeController,
controllerAs: 'vm',
bindToController: true
};
}
class ArchiveTreeController {
constructor() {
'ngInject';
...
}
...
}
现在测试代码:
var factoryFirst = DirectiveFirst.factory();
var factorySec = DirectiveSecond.factory();
var factoryThird = DirectiveThird.factory();
var directive = factoryFirst('A', 'B', 'C');
console.log(directive.constructor.name + ' ' + JSON.stringify(directive));
directive = factorySec('D', 'A', 'B', 'C');
console.log(directive.constructor.name + ' ' + JSON.stringify(directive));
directive = factoryThird('D', 'A', 'B', 'C');
console.log(directive.constructor.name + ' ' + JSON.stringify(directive));
这将返回:
DirectiveFirst {"injA":"A","injB":"B","injC":"C"}
DirectiveSecond {"injA":"A","injB":"B","injC":"C","otherInjectedProperty":"D"}
DirectiveThird {"injA":"A","injB":"B","injC":"C","otherInjectedProperty":"D"}
我的解决方案:
class myDirective {
constructor( $timeout, $http ) {
this.restrict = 'E';
this.scope = {};
this.$timeout = $timeout;
this.$http = $http;
}
link() {
console.log('link myDirective');
}
static create() {
return new myDirective(...arguments);
}
}
myDirective.create.$inject = ['$timeout', '$http'];
export { myDirective }
在主应用程序文件中
app.directive('myDirective', myDirective.create)
我刚才遇到了这个问题,我看到了这个话题。尝试了讨论中提供的一些方法,我最终以一种非常简单的方式解决了这个问题:
angular.directive('directiveFirst', DirectiveFirst.factory());
angular.directive('directiveSecond', DirectiveSecond.factory());
angular.directive('directiveThird', DirectiveThird.factory());
export default function archiveTreeDirective() {
'ngInject';
return {
restrict: 'E',
scope: {
selectedNodes: "="
},
templateUrl: 'app/components/directives/archiveTree/archiveTree.html',
controller: ArchiveTreeController,
controllerAs: 'vm',
bindToController: true
};
}
class ArchiveTreeController {
constructor() {
'ngInject';
...
}
...
}
我直接使用函数作为.directive('directiveName',factory)参数,并将其导出,然后在模块声明中导入
export default function archiveTreeDirective() {
'ngInject';
return {
restrict: 'E',
scope: {
selectedNodes: "="
},
templateUrl: 'app/components/directives/archiveTree/archiveTree.html',
controller: ArchiveTreeController,
controllerAs: 'vm',
bindToController: true
};
}
class ArchiveTreeController {
constructor() {
'ngInject';
...
}
...
}