Обновлять:
Оригинал опубликован в марте 2018 года, когда я поддерживал проект Angular, он все еще может быть полезен для тех, кто не поддерживает проекты React.
Последние несколько лет я работаю с фреймворком Angular для разных продуктов. Вот несколько решений, которые приносят мне пользу при поддержании прогресса кода Angular 1.
Используйте controllerAs вместо $scope для директив
По умолчанию все функции в directive
подключаются к $scope
. Пока функции находятся внутри области directive
в HTML, приложение будет работать.
// sample.js var sample = () => { return { controller: sampleCtrl, restrict : 'A', scope: false }; }; sampleCtrl.$inject = ['$scope']; function sampleCtrl($scope) { $scope.acc = 0; $scope.add = () => { $scope.acc++; }; } // app.js var app = angular.module('app', []); app.directive('sample', sample); <!DOCTYPE html> <html> <body> <div ng-app="app"> <div sample> <button ng-click="add()">click here</button> <h1>here goes {{acc}}</h1> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script> </body> </html>
Это разумное решение, когда нам нужно поставить только простые и понятные компоненты. Проблемы возникнут, когда мы добавим дочерний компонент
// sample.js var sample = () => { return { controller: sampleCtrl, restrict : 'A', scope: false }; }; sampleCtrl.$inject = ['$scope']; function sampleCtrl($scope) { $scope.acc = 0; $scope.add = () => { $scope.acc++; }; } // word.js var word = () => { return { controller: wordCtrl, restrict : 'A', scope: true }; }; function wordCtrl($scope) { $scope.text = 'here'; $scope.update = () => { $scope.text = $scope.text === 'here' ? 'there' : 'here'; }; } // app.js var app = angular.module('app', []); app.directive('sample', sample) .directive('word', word); <!DOCTYPE html> <html> <body> <div ng-app="app"> <div sample> <button ng-click="add()">+1</button> <div word> <button ng-click="update()">switch</button> <h1>{{text}} goes {{acc}}</h1> </div> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script> <script src="index.js"></script> </body> </html>
Теперь сложнее найти, где находятся функции add()
и update()
, так как границы sample
и word
не ясны.
Чтобы сделать это более удобным для чтения и сопровождения, мы могли бы ввести controllerAs
// sample.js var sample = () => { return { controller: sampleCtrl, controllerAs: 'sampleCtrl', restrict : 'A', scope: false }; }; sampleCtrl.$inject = ['$scope']; function sampleCtrl($scope) { let ctrl = angular.extend(this, {}); $scope.acc = 0; ctrl.add = () => { $scope.acc++; }; } // word.js var word = () => { return { controller: wordCtrl, controllerAs: 'wordCtrl', restrict : 'A', scope: true }; }; function wordCtrl($scope) { let ctrl = angular.extend(this, {}); $scope.text = 'here'; ctrl.update = () => { $scope.text = $scope.text === 'here' ? 'there' : 'here'; }; } //app.js var app = angular.module('app', []); app.directive('sample', sample) .directive('word', word); <!DOCTYPE html> <html> <body> <div ng-app="app"> <div sample> <button ng-click="sampleCtrl.add()">+1</button> <div word> <button ng-click="wordCtrl.update()">switch</button> <h1>{{text}} goes {{acc}}</h1> </div> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script> <script src="index.js"></script> </body> </html>
С этим обновлением проще найти функцию, которую вы хотите обновить, по имени контроллера.
Состояние ведения журнала, например, реакция
Теперь пришло время улучшить читаемость раздела рендеринга => {{text}}
и {{acc}}
. используя Инспектор Ng, мы можем проверить данные с живой страницы.
Это эквивалент «инструмента разработчика React» для React. Говоря о React, я обнаружил, что this.state
в реакции — это гораздо лучший способ регистрации угловых изменений, поэтому давайте реализуем это для angular 1.
// sample.js var sample = () => { return { controller: sampleCtrl, controllerAs: 'sampleCtrl', restrict : 'A', scope: false }; }; function sampleCtrl() { let ctrl = angular.extend(this, {}); ctrl.state = { acc: 0 }; ctrl.add = () => { ctrl.state.acc++; }; } // word.js var word = () => { return { controller: wordCtrl, controllerAs: 'wordCtrl', restrict : 'A', scope: true }; }; function wordCtrl() { let ctrl = angular.extend(this, {}); ctrl.state = { text: 'here' }; ctrl.update = () => { ctrl.state.text = ctrl.state.text === 'here' ? 'there' : 'here'; }; } //app.js var app = angular.module('app', []); app.directive('sample', sample) .directive('word', word); <!DOCTYPE html> <html> <body> <div ng-app="app"> <div sample> <button ng-click="sampleCtrl.add()">+1</button> <div word> <button ng-click="wordCtrl.update()">switch</button> <h1>{{wordCtrl.state.text}} goes {{sampleCtrl.state.acc}}</h1> </div> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script> <script src="index.js"></script> </body> </html>
С ng-инспекцией и состоянием наш код теперь является самостоятельным руководством для поддержки директив в angular 1.
Реализовать презентационную и контейнерную структуру
Вещи могут быть более сложными, чем это; скажем, вместо here goes
скажем here comes
. Настало время разобраться с директивными функциями с функциями представления и контейнерами.
Презентационные функции
- Беспокоится о том, как все выглядит.
- Не иметь зависимостей от остальной части приложения
- Не указывайте, как данные загружаются или изменяются.
- Являются чистыми функциями
Контейнеры
- Беспокоятся о том, как все работает.
- Предоставьте данные и поведение презентационным или другим компонентам контейнера.
- Часто имеют состояние, поскольку они, как правило, служат источниками данных.
Теперь наши презентационные функции являются чистыми функциями, поэтому, когда у нас есть ошибка в рендеринге и state
данные верны, это должны быть ошибки в презентационных функциях. С другой стороны, когда state
данные неверны, мы сможем найти ошибки в контейнерах.
// word.js var word = () => { return { controller: wordCtrl, controllerAs: 'wordCtrl', restrict : 'A', scope: true }; }; function wordCtrl() { let ctrl = angular.extend(this, {}); // Presentational ctrl.wording = (acc, text = ctrl.state.text) => { return text === 'here' ? 'here comes ' + acc : 'there goes ' + acc; }; // Container ctrl.state = { text: 'here' }; ctrl.update = () => { ctrl.state.text = ctrl.state.text === 'here' ? 'there' : 'here'; }; } <!DOCTYPE html> <html> <body> <div ng-app="app"> <div sample> <button ng-click="sampleCtrl.add()">+1</button> <div word> <button ng-click="wordCtrl.update()">switch</button> <h1>{{wordCtrl.wording(sampleCtrl.state.acc)}}</h1> </div> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script> <script src="index.js"></script> </body> </html>
Вывод
С controllerAs
, state
ведением журнала и сортировкой «функции представления и контейнера» у нас есть кодовая база с большей уверенностью в поддержке угловой.
Первоначально опубликовано на http://github.com.