Презентация Максима Ловина

advertisement
SPA – это просто, или
Знакомство с AngularJS
Максим Ловин
О себе
• В IT c 2009 года
• В DataArt c 2014 года
• Senior .NET/Front end developer
• Maxim.Lovin@dataart.com
О чем будем говорить
• Тренды разработки программного обеспечения
• Что такое SPA
• Из чего состоит AngularJS
• Демо приложение
• Модульность AngularJS приложений
• Презентационная логика и контроллеры
• Bindings, watchers, digest cycle
• Бизнес логика и сервисы
• Директивы и фильтры
• Роутинг
• Исходный код демо приложения
• Рекомендуемые материалы
Тренды разработки программного обеспечения
• Web applications
• Не зависят от платформы клиента
• Упрощается поддержка приложения
• Повышеная безопасность данных
• Стремительное развитие технологий (HTML5, FileApi, WebGL)
• Service-oriented architecture
• Mobile
• Single Page Application
Что такое SPA
Это Web-приложение, которое выполняется непосредственно на стороне
клиента в Web-браузере, написанное на HTML, JavaScript и CSS.
Преимущества SPA
• Поведение native приложения на любой платформе
• Навигация без перезагрузки страницы с сохранением истории
• Улучшенное взаимодействие между визуальными компонентами
• Меньше нагрузка на сервер, больше на клиент
• Загрузка преимущественно статического контента и только 1 раз
• Навигация/рендеринг на клиенте
• В процессе работы обращение к серверу только за данными
• Возможность работы offline
Недостатки SPA
• Сравнительно долгая инициализация приложения
• Нет возможности скрыть логику
• Нет ошибок компиляции, более сложная отладка
• Нужен более детальный Code Review и более строгие
конвенции кодирования
• Желательно периодическое профилирование приложение с
целью выявления утечек памяти и проблем с
производительностью
• Затруднительное SEO
AngularJS
AngularJS – это JavaScript framework, предназначенный для
упрощения разработки SPA на основе шаблона MVC.
Файл
Модуль
Для чего нужен
angular.js
ng
Ядро angular + множество компонент для
обеспечения базовой функциональности
angularanimate.js
ngAnimate
Обеспечивает поддержку для JavaScript,
CSS3 transition и CSS3 keyframe анимаций
angularcookies.js
ngCookies
Компоненты для работы с cookies браузера
angularresource.js
ngResource Сервис для упрощенной работы с RESTful
сервисами
angularroute.js
ngRoute
Компоненты для реализации роутинга в
приложении
angulartouch.js
ngTouch
Компоненты для работы с сенсортыми
экранами
Demo
• Скриншот
Modules
• Контейнер для различных частей приложения
• Может содержать контроллеры, сервисы, фильтры, директивы
• Конфигурирует инжектор
• Создание модуля:
angular.module(‘moduleName’, [
‘dependencyModule1’,
‘dependencyModule2’, …]);
• Обращение к модулю:
angular.module(‘moduleName’);
Modules
• Конфигурация модуля:
angular.module(‘moduleName’, […])
.config([‘srv1Provider’, ‘srv2Provider’,
function(srv1Provider, srv2Provider){
//config code
}]);
• Запуск модуля:
angular.module(‘moduleName’, […])
.run([‘srv1’, ‘srv2’, function(srv1, srv2){
//run code
}]);
• Установка модуля приложения:
<html ng-app=“moduleName”>
Modules
Angular application
rootModule
.config()
.run()
ng-app
module1
services
directives
controllers
filters
module2
services
directives
controllers
filters
module3
services
directives
controllers
filters
module4
services
directives
controllers
filters
module5
services
directives
controllers
filters
module6
services
directives
controllers
filters
Функциональная схема приложения
Angular application
View
Directives
Filters
Scope
Controller
Services
Controller
• Контроллер содержит презентационную логику
• Определяется:
angular.module(‘myModule', []).controller(‘myController',
['$scope', ‘myService', function ($scope, myService) {
$scope.inputText = myService.getInitialText();
$scope.btnTitle = ‘Do action’;
$scope.btnAction = function() {
myService.doAction($scope.inputText);
};
}]);
• Используется:
<div ng-controller=“myController”>
<input type=“text” ng-model=“inputText” />
<button ng-click=“btnAction()”>{{ btnTitle }}</button>
</div>
Dependency injection
angular.module(‘myModule', []).controller(‘myController',
function ($scope, myService) {
//presentation logic here
});
------------------------------------------------------------angular.module(‘myModule', []).controller(‘myController',
['$scope', ‘myService', function ($scope, myService) {
//presentation logic here
}]);
------------------------------------------------------------var MyController = function($scope, myService){
//presentation logic here
}
MyController.$inject = ['$scope', ‘myService'];
angular.module(‘myModule', [])
.controller(‘myController', MyController);
One way bindings
$scope.someValue = ‘<span class=“styled-text”>Some value</span>’;
$scope.anotherValue = function (){ return ‘1234567890123’; };
---------------------------------------------------------<p>{{ someValue }}</p>
<p ng-bind=“someValue” />
<!-- <span class=“styled-text”>Some value</span> -->
<p ng-bind-html=“someValue” /> <!-- module ngSanitize required -->
<!-- Some value -->
<p>{{ anotherValue()|currency:‘€’ }}</p>
<!-- €1,234,567,890,123.00 -->
<p ng-bind=“anotherValue()|date:‘medium’” />
<!-- Feb 14, 2009 1:31:30 AM -->
Two way bindings
• Реализуется при помощи директивы ng-model
• Применяется с любыми директивами, подразумевающими
пользовательский ввод (‘input’, ‘select’, ‘textarea’)
• Предоставляет возможность валидации
• Хранит состояние сонтрола (valid/invalid, dirty/pristine,
touched/untouched, validation errors) и назначает
соответствующие классы (ng-valid, ng-invalid, ng-dirty, ngpristine, ng-touched, ng-untouched )
---------------------------------------------------------$scope.someValue = ‘’;
---------------------------------------------------------<input type=“text” ng-model=“someValue” />
<p ng-bind=“someValue” />
Two way bindings options
• Определяются с помощью директивы ng-model-options
• Позволяют сконфигурировать:
• По какому событию привязывать данные (updateOn)
• Задержку привязки по каждому событию (debounce)
• Допускать ли невалидные данные (allowInvalid)
• Является ли привязываемое значение функцией (getterSetter)
• Локаль даты и времени для input[type=“date”] и др. (timezone)
---------------------------------------------------------<input type=“text”
ng-model=“someValue”
ng-model-options=“{updateOn: ‘blur’, debounce: {‘blur’: 500}}” />
Watchers
• Watching by reference
• Watching collection contents
• Watching by value
---------------------------------------------------------$scope.users = [{name:‘Mary’,points:100}, {name:‘Bob’,points:220}];
var newUsers = [{name:‘John’,points:330}, {name:‘Dee’,points:180}];
function listener(newValue, oldValue){}
$scope.$watch(‘users’, listener); //by reference
$scope.$watchCollection(‘users’, listener); //collection
$scope.$watch(‘users’, listener, true); //by value
$scope.users = newUsers; //by reference, collection, by value
$scope.users.push({name:‘Alex’,points:320}); //collection, by value
$scope.users[0].points = 150; //by value
Digest cycle
• Обновляет биндинги для изменившейся модели
• Обрабатывает watchers
• Начинает работу по любому событию, попавшему в контекст
angular приложения, с помощью $scope.$digest() или
$scope.$apply()
---------------------------------------------------------$scope.name = ‘Foo’;
$scope.changeName = function() { $scope.name = ‘Bar’; };
---------------------------------------------------------<p ng-bind=“name” />
<button ng-click=“changeName()”>Change name</button>
----------------------------------------------------------
Loop through watch list
oldVal != newVal
Run
Yes
Run watcher
listener or mark
binding as dirty
oldVal = newVal
Yes
did we have at
least one dirty?
No
Update DOM
Services
• Содержат бизнес логику приложения
• Инжектируются в контроллеры, другие сервисы, директивы и
фильтры
• Singletons – имеют единственный экземпляр
• Lazily instantiated – инстанциируются по первому запросу
• Виды:
• constant
• value
• factory
• service
• provider
Constant
• Содержит не изменяемое значение
• Может быть в виде строки, числа, массива, объекта или функции
• Может настраиваться в .config() модуля
• Определяется:
angular.module(‘myModule', [])
.constant(‘myConstant', {value1: ‘someVal’, value2: 21});
• Настраивается:
angular.module(‘myApp', [‘myModule'])
.config([‘myConstant', function(c){
c.value1 = ‘anotherVal’;
}]);
Value
• Содержит изменяемое значение
• Может быть в виде строки, числа, массива, объекта или функции
• Определяется:
angular.module(‘myModule', [])
.value(‘myValue', {value1: ‘someVal’, value2: 21});
Factory, Service
angular.module(‘myModule', [])
.factory(‘myFactory', [‘dependency1', ‘dep2', function (d1, d2){
var privateVariable = ‘’;
function doSomethingPrivate(){
d1.doAction(privateVariable);
}
return {
doSomething: function (p){
privateVariable = p;
doSomethingPrivate();
}
};
}])
.service(‘myService', [‘dependency1', ‘dep2', function (d1, d2){
var self = this;
var privateVariable = ‘’;
function doSomethingPrivate(){
d1.doAction(privateVariable);
}
self.doSomething = function (p){
privateVariable = p;
doSomethingPrivate();
};
}]);
Provider
• Может настраиваться в .config() модуля
• Определяется:
angular.module(‘myModule', []).provider(‘myProvider', function (){
var privateVarConfig = ‘’;
this.configurePrivate = function(val){
privateVarConfig = val;
};
function MyServiceConstructor(d1, d2, privateVariable){
function doSomethingPrivate() {
d1.doAction(privateVariable);
}
this.doSomething = function (p){
privateVariable = p;
doSomethingPrivate();
};
}
this.$get = [‘dependency1', ‘dep2', function (d1, d2){
return new MyServiceConstructor(d1, d2, privateVarConfig);
}];
});
Services decoration
• Внедряется в процесс инстанциирования сервиса
• Позволяет изменить или расширить функциональность сервиса
• Реализуется с помощью сервиса $provide
• Можно декорировать value, service, factory, provider
• Определяется в конфиге модуля:
angular.module(‘myApp', [‘myModule’])
.config([‘$provide’, function(provide){
provide.decorator(‘myService’, [‘$delegate’, function(d){
d.anotherFunction = function(){};
return d;
}]);
}]);
Основные сервисы angularjs
• $cacheFactory – работа с memory cache
• $compile – компеляция темплейтов и их связка со scope
• $document, $window – обертки над соответствующими
объектами браузера
• $http – коммуникация с удаленным сервером посредством
XMLHttpRequest или JSONP
• $injector – контейнер зависимостей
• $interval, $timeout – обертки над setInterval() и setTimeout()
функциями объекта window
• $location – работа со строкой адреса браузера
• $q – помогает работать с асинхронными функциями
$q
this.doSomethingAsync = function(){
var deferred = $q.defer();
//run async operation ($http, $timeout, etc)
//call deferred.resolve(result) if success
//call deferred.reject(reason) if error
return deferred.promise;
};
---------------------------------------------------function successCallback(result){/* handle result */}
function errorCallback(reason) {/* handle error */}
myService.doSomethingAsync().then(successCallback, errorCallback);
---------------------------------------------------this.getDataAsync = function(inputParam){
if(!inputParam){ return $q.reject(‘Incorrect input param’); }
if(hasData(inputParam)){ return $q.when(getData(inputParam)); }
return $http.get(‘some/url/’+inputParam).then(function(data){
cacheData(inputParam, data);
return getData(inputParam);
});
}
Directives
• Реализуют UI логику
• Определяются:
angular.module(‘myModule’, [])
.directive(‘myDirective’, [function () {
return {
restrict: ‘AE’, //CM
templateUrl: ‘some/template/path.html’,
scope: {
someTextParam: ‘@title’,
someObjectParam: ‘=’
},
link: function ($scope, $element, $attrs) {
}
};
}]);
• Используются:
<div my-directive title=“Title: {{ title }}”
some-object-param=“obj” />
<my-directive title=“Title: {{ title }}” some-object-param=“obj” />
Основные директивы angularjs
• Обработка событий DOM в контексте angular digest
ng-blur, ng-change, ng-click, ng-copy, ng-cut, ng-dblclick, ng-focus, ngkeydown, ng-keypress, ng-mousedown, ng-mouseenter, ng-mouseleave,
ng-mousemove, ng-mouseover, ng-mouseup, ng-paste, ng-submit
• Предотвращение не валидного запроса из-за использования
биндингов
ng-href, ng-src, ng-srcset
<img src=“http://www.some.site.com/path/{{urlPart}}.jpg” />
<img ng-src=“http://www.some.site.com/path/{{urlPart}}.jpg” />
• Генерация элементов
ng-if, ng-include, ng-repeat, ng-switch
• Управление стилями элементов
ng-class, ng-class-even, ng-class-odd, ng-cloak, ng-hide, ng-show, ng-style
• Управление состоянием элементов
ng-checked, ng-disabled, ng-readonly, ng-selected
Filters
• Предназначены для преобразования значений модели в
удобный для пользователя вид
• Определяются:
angular.module(‘myModule’, [])
.filter(‘myFilter’, [function () {
return function (value, param1, param2) {
};
}]);
• Используются:
<p ng-bind=“someValue | myFilter : ‘param1’” />
• Фильтры в составе Angularjs:
• currency (symbol, fractionSize)
• date (format, timezone)
• filter (expression, comparator), orderBy (expression, reverse)
• json (spacing)
• limitTo (limit)
• lowercase, uppercase
• number (fractionSize)
ngRoute
• Модуль, преднозначеный для реализации навигации
• Состоит из директивы ngView и сервисов $route и $routeParams
• Определение роутов:
angular.module(‘myApp’, [‘ngRoute’])
.config([‘$routeProvider’, ‘$locationProvider’,
function ($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider.when(‘/some/url’, {
templateUrl: ‘path/to/view/template.html’,
controller: ‘viewControllerName’
});
$routeProvider.otherwise(‘/home/page’);
}]);
Demo
Рекомендуемые материалы
• “AngularJS: Up And Running”, Shyam Seshadri and Brad Green,
O’Reilly, September 2014, First Edition
• https://www.youtube.com/user/angularjs
• https://docs.angularjs.org/guide
• https://docs.angularjs.org/api
• https://angular-ui.github.io/
• UI-Bootstrap
• UI-Router
• UI-Grid
• UI-Gmap
Спасибо за внимание
Вопросы и ответы
Download