在Typescript中创build一个AngularJS 1.5组件的最佳实践是什么?
我正在使用Angular 1.5中的.component()
语法进行试验。
看起来,最新的方式是在组件中编码控制器,而不是单独的文件,我可以看到,鉴于组件样板是最小的优点。
问题是我一直编写我的控制器作为打字稿类,并希望继续这样做,因为这似乎是符合Angular2。
我最大的努力就是这样的:
export let myComponent = { template: ($element, $attrs) => { return [ `<my-html>Bla</my-html>` ].join('') }, controller: MyController }; class MyController { }
它的工作,但它不是优雅的。 有没有更好的办法?
如果你想完全采用Angular 2的方法,你可以使用:
module.ts
import { MyComponent } from './MyComponent'; angular.module('myModule', []) .component('myComponent', MyComponent);
MyComponent.ts
import { Component } from './decorators'; @Component({ bindings: { prop: '<' }, template: '<p>{{$ctrl.prop}}</p>' }) export class MyComponent { prop: string; constructor(private $q: ng.IQService) {} $onInit() { // do something with this.prop or this.$q upon initialization } }
decorators.ts
/// <reference path="../typings/angularjs/angular.d.ts" /> export const Component = (options: ng.IComponentOptions) => { return controller => angular.extend(options, { controller }); };
我正在使用一个简单的Typescript装饰器来创build组件
function Component(moduleOrName: string | ng.IModule, selector: string, options: { controllerAs?: string, template?: string, templateUrl?: string }) { return (controller: Function) => { var module = typeof moduleOrName === "string" ? angular.module(moduleOrName) : moduleOrName; module.component(selector, angular.extend(options, { controller: controller })); } }
所以我可以像这样使用它
@Component(app, 'testComponent', { controllerAs: 'ct', template: ` <pre>{{ct}}</pre> <div> <input type="text" ng-model="ct.count"> <button type="button" ng-click="ct.decrement();">-</button> <button type="button" ng-click="ct.increment();">+</button> </div> ` }) class CounterTest { count = 0; increment() { this.count++; } decrement() { this.count--; } }
你可以尝试一个工作jsbin在这里http://jsbin.com/jipacoxeki/edit?html,js,output
这是我使用的模式:
ZippyComponent.ts
import {ZippyController} from './ZippyController'; export class ZippyComponent implements ng.IComponentOptions { public bindings: { bungle: '<', george: '<' }; public transclude: boolean = false; public controller: Function = ZippyController; public controllerAs: string = 'vm'; public template: string = require('./Zippy.html'); }
ZippyController.ts
export class ZippyController { bungle: string; george: Array<number>; static $inject = ['$timeout']; constructor (private $timeout: ng.ITimeoutService) { } }
Zippy.html
<div class="zippy"> {{vm.bungle}} <span ng-repeat="item in vm.george">{{item}}</span> </div>
main.ts
import {ZippyComponent} from './components/Zippy/ZippyComponent'; angular.module('my.app', []) .component('myZippy', new ZippyComponent());
我正在同样的问题挣扎,并把我的解决scheme放在这篇文章中:
http://almerosteyn.github.io/2016/02/angular15-component-typescript
module app.directives { interface ISomeComponentBindings { textBinding: string; dataBinding: number; functionBinding: () => any; } interface ISomeComponentController extends ISomeComponentBindings { add(): void; } class SomeComponentController implements ISomeComponentController { public textBinding: string; public dataBinding: number; public functionBinding: () => any; constructor() { this.textBinding = ''; this.dataBinding = 0; } add(): void { this.functionBinding(); } } class SomeComponent implements ng.IComponentOptions { public bindings: any; public controller: any; public templateUrl: string; constructor() { this.bindings = { textBinding: '@', dataBinding: '<', functionBinding: '&' }; this.controller = SomeComponentController; this.templateUrl = 'some-component.html'; } } angular.module('appModule').component('someComponent', new SomeComponent()); }
我正在使用以下模式与打字稿使用angular1.5 组件
class MyComponent { model: string; onModelChange: Function; /* @ngInject */ constructor() { } modelChanged() { this.onModelChange(this.model); } } angular.module('myApp') .component('myComponent', { templateUrl: 'model.html', //template: `<div></div>`, controller: MyComponent, controllerAs: 'ctrl', bindings: { model: '<', onModelChange: "&" } });
我build议不要使用定制的解决scheme,而是使用ng-metadata
库来代替。 你可以在https://github.com/ngParty/ng-metadatafind它。; 像这样你的代码是最适合Angular 2的。 正如在自述中所述的那样
没有黑客。 没有覆盖。 生产准备。
我刚从这个答案中使用了一个自定义的解决scheme之后切换,但是如果您立即使用这个库,则会更容易。 否则,你将不得不迁移所有小的语法变化。 一个例子是这里的其他解决scheme使用语法
@Component('moduleName', 'selectorName', {...})
而Angular 2使用
@Component({ selector: ..., ... })
所以,如果你不使用ng-metadata
,你将会大大增加后面你的代码库的迁移工作。
编写组件的最佳实践的完整示例如下 :
// hero.component.ts import { Component, Inject, Input, Output, EventEmitter } from 'ng-metadata/core'; @Component({ selector: 'hero', moduleId: module.id, templateUrl: './hero.html' }) export class HeroComponent { @Input() name: string; @Output() onCall = new EventEmitter<void>(); constructor(@Inject('$log') private $log: ng.ILogService){} }
(从ng元数据收件复制)
我相信一个好方法是使用angular-ts-decorators 。 有了它,你可以像这样在AngularJS中定义组件:
import { Component, Input, Output } from 'angular-ts-decorators'; @Component({ selector: 'myComponent', templateUrl: 'my-component.html }) export class MyComponent { @Input() todo; @Output() onAddTodo; $onChanges(changes) { if (changes.todo) { this.todo = {...this.todo}; } } onSubmit() { if (!this.todo.title) return; this.onAddTodo({ $event: { todo: this.todo } }); } }
然后使用以下命令将它们注册到模块中:
import { NgModule } from 'angular-ts-decorators'; import { MyComponent } from './my-component'; @NgModule({ declarations: [MyComponent] }) export class MyModule {}
如果你想检查一个真正的应用程序使用它的例子,你可以检查这一个 。