使用 ES2015 开发 Angular1.x 应用指南
来自 @toddmotto 团队的编码指南 Angular 的编码风格以及架构已经使用ES2015进行重写,这些在Angular 1.5+的变化可以更好帮助您的更好的升级到Angular2.。 老版本的指南你可以在这里找到,在这里你能看到最新的. 模块架构Angular 中的每一个模块都是一个模块组件。一个模块组件囊括了逻辑,模版,路由和子组件。 Module 基本概念在模块的设计直接反映到我们的文件夹结构,从而保证我们项目的可维护性和可预测性。 根模块根模块会启动一个根组件,整个组件主要定义了整个应用的基本的元素和路由出口,例如使用 // app.component.js const AppComponent = { template: ` <header> Hello world </header> <div> <div ui-view></div> </div> <footer> Copyright MyApp 2016. </footer> ` }; export default AppComponent; 我们导入 // app.js import angular from 'angular'; import uiRouter from 'angular-ui-router'; import AppComponent from './app.component'; import Components from './components/components'; import Common from './common/common'; const root = angular .module('app',[ Components,Common,uiRouter ]) .component('app',AppComponent); export default root; 组件模块一个组件模块就是引用所有课重复使用的组件容器。上面我们可以了解我们如何导入组件和将它们注入到根模块, import angular from 'angular'; import Calendar from './calendar'; import Events from './events'; const components = angular .module('app.components',[ Calendar,Events ]) .name; export default components; 公共模块公共模块为所有的应用提供一些特殊组件的引用,我们不希望它能够在另一个应用程序中使用。比如布局,导航和页脚。 import angular from 'angular'; import Nav from './nav'; import Footer from './footer'; const common = angular .module('app.common',[ Nav,Footer ]) .name; export default common; 低级别的模块低层次的模块是一些独立的组件,它们包含逻辑和功能。这些将分别定义成模块,被引入到较高层次模块中, import angular from 'angular'; import uiRouter from 'angular-ui-router'; import CalendarComponent from './calendar.component'; const calendar = angular .module('calendar',[ uiRouter ]) .component('calendar',CalendarComponent) .config(($stateProvider,$urlRouterProvider) => { $stateProvider .state('calendar',{ url: '/calendar',component: 'calendar' }); $urlRouterProvider.otherwise('/'); }) .name; export default calendar; 文件命名规范使用小写并保持命名的简介,比如使用组件名称时,e.g. index.js calendar.controller.js calendar.component.js calendar.service.js calendar.directive.js calendar.filter.js calendar.spec.js 返回目录 易于扩展的文件结构文件目录结构实际上十分重要,它有利于我们更好的扩展和预测。下面的例子展示了模块组件的基本架构。 ├── app/ │ ├── components/ │ │ ├── calendar/ │ │ │ ├── index.js │ │ │ ├── calendar.controller.js │ │ │ ├── calendar.component.js │ │ │ ├── calendar.service.js │ │ │ ├── calendar.spec.js │ │ │ └── calendar-grid/ │ │ │ ├── index.js │ │ │ ├── calendar-grid.controller.js │ │ │ ├── calendar-grid.component.js │ │ │ ├── calendar-grid.directive.js │ │ │ ├── calendar-grid.filter.js │ │ │ └── calendar-grid.spec.js │ │ └── events/ │ │ ├── index.js │ │ ├── events.controller.js │ │ ├── events.component.js │ │ ├── events.directive.js │ │ ├── events.service.js │ │ ├── events.spec.js │ │ └── events-signup/ │ │ ├── index.js │ │ ├── events-signup.controller.js │ │ ├── events-signup.component.js │ │ ├── events-signup.service.js │ │ └── events-signup.spec.js │ ├── common/ │ │ ├── nav/ │ │ │ ├── index.js │ │ │ ├── nav.controller.js │ │ │ ├── nav.component.js │ │ │ ├── nav.service.js │ │ │ └── nav.spec.js │ │ └── footer/ │ │ ├── index.js │ │ ├── footer.controller.js │ │ ├── footer.component.js │ │ ├── footer.service.js │ │ └── footer.spec.js │ ├── app.js │ └── app.component.js └── index.html 顶级目录 仅仅包含了 组件组件的基本概念组件实际上就是带有控制器的模板。他们即不是指令,也不应该使用组件代替指令,除非你正在用控制器升级“模板指令”, 支持的属性下面是一些
控制器控制器应该只与组件一起使用。如果你觉得你需要一个控制器,你真正需要的可能是一个无状态的组件来管理特定的行为。 这里有一些使用
One-way dataflow and Events单向数据流已经在Angular1.5中引入了,并且重新定义了组件之间的通信。 关于单向数据流的一些小建议:
有状态的组件什么是“有状态的组件”
下面的是一个状态组件案例,它和一个低级别的模块组件共同完成(这只是演示,为了精简省略的一些代码) /* ----- todo/todo.component.js ----- */ import controller from './todo.controller'; const TodoComponent = { controller,template: ` <div class="todo"> <todo-form todo="$ctrl.newTodo" on-add-todo="$ctrl.addTodo($event);"> <todo-list todos="$ctrl.todos"></todo-list> </div> ` }; export default TodoComponent; /* ----- todo/todo.controller.js ----- */ class TodoController { constructor(TodoService) { this.todoService = TodoService; } $onInit() { this.newTodo = { title: '',selected: false }; this.todos = []; this.todoService.getTodos.then(response => this.todos = response); } addTodo({ todo }) { if (!todo) return; this.todos.unshift(todo); this.newTodo = { title: '',selected: false }; } } TodoController.$inject = ['TodoService']; export default TodoController; /* ----- todo/index.js ----- */ import angular from 'angular'; import TodoComponent from './todo.component'; const todo = angular .module('todo',[]) .component('todo',TodoComponent) .name; export default todo; 这个例子显示了一个有状态的组件,在控制器哪通过服务获取状态,然后再将它传递给无状态的子组件。注意这里并没有在模版使用指令比如 无状态的组件什么是无状态的组件
下面是一个无状态组件的例子 (我们使用 /* ----- todo/todo-form/todo-form.component.js ----- */ import controller from './todo-form.controller'; const TodoFormComponent = { bindings: { todo: '<',onAddTodo: '&' },controller,template: ` <form name="todoForm" ng-submit="$ctrl.onSubmit();"> <input type="text" ng-model="$ctrl.todo.title"> <button type="submit">Submit</button> </form> ` }; export default TodoFormComponent; /* ----- todo/todo-form/todo-form.controller.js ----- */ class TodoFormController { constructor(EventEmitter) {} $onChanges(changes) { if (changes.todo) { this.todo = Object.assign({},this.todo); } } onSubmit() { if (!this.todo.title) return; // with EventEmitter wrapper this.onAddTodo( EventEmitter({ todo: this.todo }); ); // without EventEmitter wrapper this.onAddTodo({ $event: { todo: this.todo } }); } } TodoFormController.$inject = ['EventEmitter']; export default TodoFormController; /* ----- todo/todo-form/index.js ----- */ import angular from 'angular'; import TodoFormComponent from './todo-form.component'; const todoForm = angular .module('todo') .component('todo',TodoFormComponent) .value('EventEmitter',payload => ({ $event: payload}); export default todoForm; 请注意 路由组件什么是路由组件
*数据流入到组件是通过路由分解获得 (当然在控制器中我们通过服务获得) 在这个例子中,我们将利用现有<TODO>组件,我们会重构它,使用路由定义和以及组件上的数据绑定接收数据(在这里我们我们是通过 /* ----- todo/todo.component.js ----- */ import controller from './todo.controller'; const TodoComponent = { bindings: { todoData: '<' },template: ` <div class="todo"> <todo-form todo="$ctrl.newTodo" on-add-todo="$ctrl.addTodo($event);"> <todo-list todos="$ctrl.todos"></todo-list> </div> ` }; export default TodoComponent; /* ----- todo/todo.controller.js ----- */ class TodoController { constructor() {} $onInit() { this.newTodo = { title: '',selected: false }; } $onChanges(changes) { if (changes.todoData) { this.todos = Object.assign({},this.todoData); } } addTodo({ todo }) { if (!todo) return; this.todos.unshift(todo); this.newTodo = { title: '',selected: false }; } } export default TodoController; /* ----- todo/todo.service.js ----- */ class TodoService { constructor($http) { this.$http = $http; } getTodos() { return this.$http.get('/api/todos').then(response => response.data); } } TodoService.$inject = ['$http']; export default TodoService; /* ----- todo/index.js ----- */ import angular from 'angular'; import TodoComponent from './todo.component'; import TodoService from './todo.service'; const todo = angular .module('todo',TodoComponent) .service('TodoService',TodoService) .config(($stateProvider,$urlRouterProvider) => { $stateProvider .state('todos',{ url: '/todos',component: 'todo',resolve: { todoData: TodoService => TodoService.getTodos(); } }); $urlRouterProvider.otherwise('/'); }) .name; export default todo; 指令基本概念指令给予了我们的模板,scope ,与控制器绑定,链接和许多其他的事情。这些的使用使我们慎重考虑 使用指令的小建议:
返回目录 推荐的属性由于指令支持了大多数
常量 和 类下面有几个使用es2015和指令的方法,无论是带有箭头函数,更容易的操作,或使用ES2015 下面是一个恒在箭头函数的表达式 /* ----- todo/todo-autofocus.directive.js ----- */ import angular from 'angular'; const TodoAutoFocus = ($timeout) => ({ restrict: 'A',link($scope,$element,$attrs) { $scope.$watch($attrs.todoAutofocus,(newValue,oldValue) => { if (!newValue) { return; } $timeout(() => $element[0].focus()); }); } }); TodoAutoFocus.$inject = ['$timeout']; export default TodoAutoFocus; /* ----- todo/index.js ----- */ import angular from 'angular'; import TodoComponent from './todo.component'; import TodoAutofocus from './todo-autofocus.directive'; const todo = angular .module('todo',TodoComponent) .directive('todoAutofocus',TodoAutoFocus) .name; export default todo; 或者用ES2015 Class(注意在注册指令时手动调用 /* ----- todo/todo-autofocus.directive.js ----- */ import angular from 'angular'; class TodoAutoFocus { constructor() { this.restrict = 'A'; } link($scope,oldValue) => { if (!newValue) { return; } $timeout(() => $element[0].focus()); }); } } TodoAutoFocus.$inject = ['$timeout']; export default TodoAutoFocus; /* ----- todo/index.js ----- */ import angular from 'angular'; import TodoComponent from './todo.component'; import TodoAutofocus from './todo-autofocus.directive'; const todo = angular .module('todo',() => new TodoAutoFocus) .name; export default todo; 服务基本理论服务本质上是包含业务逻辑的容器,而我们的组件不应该直接进行请求。服务包含其它内置或外部服务,如 构建服务Class下面的 /* ----- todo/todo.service.js ----- */ class TodoService { constructor($http) { this.$http = $http; } getTodos() { return this.$http.get('/api/todos').then(response => response.data); } } TodoService.$inject = ['$http']; export default TodoService; /* ----- todo/index.js ----- */ import angular from 'angular'; import TodoComponent from './todo.component'; import TodoService from './todo.service'; const todo = angular .module('todo',TodoService) .name; export default todo; 返回目录 ES2015 以及相关工具ES2015
工具
状态管理考虑使用 Redux 用于 数据管理.
资源
文档关于Angular API Angular documentation.
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |