在 Typescript 中将 angularjs 指令实现为类
Posted
技术标签:
【中文标题】在 Typescript 中将 angularjs 指令实现为类【英文标题】:Implementing angularjs directives as classes in Typescript 【发布时间】:2014-06-25 12:06:17 【问题描述】:因此,在查看了 typescript 中 angularjs 指令的一些示例之后,似乎大多数人都同意在实现它们时使用函数而不是类。
我希望将它们作为一个类并尝试按如下方式实现它们:
module directives
export class search implements ng.IDirective
public restrict: string;
public templateUrl: string;
constructor()
this.restrict = 'AE';
this.templateUrl = 'directives/search.html';
public link($scope: ng.IScope, element: JQuery, attributes: ng.IAttributes)
element.text("Hello world");
现在这工作正常。但是,我需要一个具有某些属性的隔离范围,并且我正在努力找出如何将其包含在类本身中。
逻辑决定了,因为我可以拥有
public restrict: string;
public templateUrl: string;
我应该能够拥有类似的东西:
public scope;
但我不确定这是否正确或如何从那里继续(即如何将属性添加到范围)。
有人知道怎么解决吗? (希望,如果可能,不必恢复到函数)
谢谢,
【问题讨论】:
【参考方案1】:将指令创建为类可能会有问题,因为您仍然需要使用工厂函数来包装其实例化。例如:
export class SomeDirective implements ng.IDirective
public link = () =>
constructor()
什么不起作用
myModule.directive('someDirective', SomeDirective);
因为指令不是使用“new”调用的,而是作为工厂函数调用的。这将导致您的构造函数实际返回的内容出现问题。
做什么(带有警告)
myModule.directive(() => new SomeDirective());
如果您不涉及任何 IoC,这可以正常工作,但是一旦您开始引入可注射,您必须为您的工厂函数和指令构造函数维护重复的参数列表。
export class SomeDirective implements ng.IDirective
...
constructor(someService: any)
myModule.directive('someDirective', ['someService', (someService) => new SomeDirective(someService)]);
如果您愿意,这仍然是一个选项,但了解指令注册的实际使用方式很重要。
另一种方法
angular 实际期望的东西是一个指令工厂函数,所以类似于:
export var SomeDirectiveFactory = (someService: any): ng.IDirective =>
return
link: () => ...
;
SomeDirectiveFactory.$inject = ['someService']; //including $inject annotations
myModule.directive('someDirective', SomeDirectiveFactory);
这具有允许使用 $inject 注释的好处,因为在这种情况下 Angular 需要它在工厂函数上。
您也可以始终从工厂函数返回您的类的实例:
export var SomeDirectiveFactory = (someService: any): ng.IDirective =>
return new SomeDirective(someService);
SomeDirectiveFactory.$inject = ['someService']; //including $inject annotations
但实际上取决于您的用例,您可以使用多少重复的参数列表等。
【讨论】:
【参考方案2】:假设您所拥有的东西在没有孤立作用域的情况下工作,以下内容应该适用于孤立作用域:
module directives
export class search implements ng.IDirective
public restrict = 'AE';
public templateUrl = 'directives/search.html';
public scope =
foo:'=',
bar:'@',
bas:'&'
;
public link($scope: ng.IScope, element: JQuery, attributes: ng.IAttributes)
element.text("Hello world");
【讨论】:
太棒了!谢谢巴萨拉特! 如何注册指令? 再想一想,这是否会引起麻烦,因为指令工厂不是“新的”,而是作为函数调用的?特别是构造函数不会返回类以外的东西吗? 我编写了一个实用程序,可用于在 TypeScript 中启用这种基于类的指令定义。 An example directive 可以找到解释here 要注册这个,@bingle 解释如下:myModule.directive("angEnter", () => new MyDirective);
【参考方案3】:
这是我的建议:
指令:
import directive from '../../decorators/directive';
@directive('$location', '$rootScope')
export class StoryBoxDirective implements ng.IDirective
public templateUrl:string = 'src/module/story/view/story-box.html';
public restrict:string = 'EA';
public scope:Object =
story: '='
;
public link:Function = (scope:ng.IScope, element:ng.IAugmentedJQuery, attrs:ng.IAttributes):void =>
// console.info(scope, element, attrs, this.$location);
scope.$watch('test', () =>
return null;
);
;
constructor(private $location:ng.ILocationService, private $rootScope:ng.IScope)
// console.log('Dependency injection', $location, $rootScope);
模块(寄存器指令...):
import App from '../../App';
import StoryBoxDirective from './../story/StoryBoxDirective';
import StoryService from './../story/StoryService';
const module:ng.IModule = App.module('app.story', []);
module.service('storyService', StoryService);
module.directive('storyBox', <any>StoryBoxDirective);
装饰器(添加注入和生产指令对象):
export function directive(...values:string[]):any
return (target:Function) =>
const directive:Function = (...args:any[]):Object =>
return ((classConstructor:Function, args:any[], ctor:any):Object =>
ctor.prototype = classConstructor.prototype;
const child:Object = new ctor;
const result:Object = classConstructor.apply(child, args);
return typeof result === 'object' ? result : child;
)(target, args, () =>
return null;
);
;
directive.$inject = values;
return directive;
;
我正在考虑将module.directive(...)
、module.service(...)
移至类文件,例如StoryBoxDirective.ts
但还没有做出决定和重构 ;)
您可以在此处查看完整的工作示例:https://github.com/b091/ts-skeleton
指令在这里:https://github.com/b091/ts-skeleton/blob/master/src/module/story/StoryBoxDirective.ts
【讨论】:
【参考方案4】:最后我得到了一个指令作为类加继承。在派生指令中,我扩展了范围并定义了 templateUrl。 您可以覆盖基本指令中的任何方法 . key 是从构造函数返回指令的实例。Angularjs 调用没有 new 关键字的构造函数。在这种情况下,this 属于 window 类型 我换了几行来检查 this 的实例类型,如果是窗口,我会创建一个新的指令实例。 (参见下面示例中的 Activator 类)
module Realty.directives
export class BaseElementWithLabel implements ng.IDirective
public restrict = 'E';
public replace = true;
public scope =
label: '@',
model: '=',
icon: '@',
readonlyElement: '=',
remark: '@'
constructor(extendedScope)
if (!(this instanceof Window))
extendedScope = extendedScope || ;
this.scope = angular.extend(this.scope, extendedScope);
link(scope: ng.IScope, element: ng.IAugmentedJQuery, attributes: ng.IAttributes, controller, transclude)
scope['vm'] = ;
module Realty.directives
export class textareaWithLabel extends Realty.directives.BaseElementWithLabel implements ng.IDirective
templateUrl = 'directives/element-form/textarea-with-label-template.html';
constructor()
super(
rows: '@'
);
return Realty.Activator.Activate(this, textareaWithLabel, arguments);
;
;
module Realty
export class Activator
public static Activate(instance: any, type, arguments)
if (instance instanceof type)
return instance;
return new(type.bind.apply(type, Array.prototype.concat.apply([null], arguments)));
【讨论】:
以上是关于在 Typescript 中将 angularjs 指令实现为类的主要内容,如果未能解决你的问题,请参考以下文章
Angularjs+Typescript 指令实现 $compile
在 AngularJS 上使用 Typescript 的指令中控制器的范围