Как стать автором
Обновить

Angular 2.0.0-alpha для тех, кто не в силах ждать

Время на прочтение9 мин
Количество просмотров54K

Совсем недавно (5-6 марта) прошла конференция ng-conf, и много докладов на ней было посвящено грядущему релизу Angular 2, на нескольких из них даже показали альфа версию. Конечно же после прослушивания очень захотелось опробовать его лично. Если вам тоже не терпится — прошу под кат.

В этой статье мы разберёмся, где взять билд альфа версии Angular 2.0, создадим на нём небольшое приложение — To-do list, и запустим его в браузере без полной поддержки ECMAScript 6.

Angular 2 очень сильно отличается от нынешней версии, переосмыслено практически всё. Многие из отличий вытекают из того, что он на всю катушку использует ES6 с аннотациями и типами, разработчики называют этот язык AtScript. Теперь же, судя по всему, команда Angular начала плотно сотрудничать с Microsoft и разработка будет вестись на TypeScript, и после выхода его версии 1.5, туда будет полностью включен AtScript.

Приложение Angular 2 теперь состоит из компонентов и представляет из себя их дерево. Идея похожа на Web-components, даже разметка Angular 2 компонентов помещается в Shadow DOM. Причём если вы соберётесь использовать в своём приложении Web-components, или, например, Polymer – то синтаксис ничем не будет отличаться от использования ваших собственных Angular 2 компонентов. Сами компоненты представляют из себя ES6 классы с аннотациями, никакого специального синтаксиса как, например, для директив в версии 1.х не требуется. Сервисы теперь тоже стали обычными классами, а благодаря поддержке типизации в AtScript, инъектировать их можно по типу, без использования синтаксиса .$inject или ngAnnotate.

Давайте сейчас попробуем создать наше первое To-do приложение и по ходу дела разберёмся, что да как.

На сегодня ни один браузер не поддерживает весь тот функционал, который нужен Angular 2 для работы, поэтому нам понадобится целый ворох инструментов:

Чтобы всем желающим пощупать альфу не приходилось ставить это всё по-отдельности, разработчики собрали quick start. Его можно установить набрав в папке проекта:

git clone https://github.com/angular/quickstart.git 

Теперь все необходимое лежит у нас в папке quickstart, а для красоты добавим ещё angular-material, но использовать из него будем, разумеется, только css:

bower install angular-material 

Теперь создадим в проекте файл index.html:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>To Do</title>
    <script src="/quickstart/dist/es6-shim.js"></script>
    <link href="bower_components/angular-material/angular-material.css" rel="stylesheet" />
</head>
<body layout="row">
    <style>
        md-progress-circular.md-default-theme.blue .md-inner .md-right .md-half-circle {
            border-right-color: #039be5;
        }

        md-progress-circular.md-default-theme.blue .md-inner .md-left .md-half-circle, md-progress-circular.md-default-theme .md-inner .md-right .md-half-circle {
            border-top-color: #039be5;
        }

        md-progress-circular.md-default-theme.blue .md-inner .md-left .md-half-circle {
            border-left-color: #039be5;
        }

        md-progress-circular.md-default-theme.blue .md-inner .md-gap {
            border-top-color: #039be5;
            border-bottom-color: #039be5;
        }
    </style>
    <app flex layout="row" layout-fill>
        <div layout-fill layout="row" layout-align="center center" layout-margin>
            <md-progress-circular md-mode="indeterminate" class="md-default-theme blue" style="-webkit-transform: scale(1);">
                <div class="md-spinner-wrapper">
                    <div class="md-inner">
                        <div class="md-gap">
                        </div>
                        <div class="md-left">
                            <div class="md-half-circle"></div>
                        </div>
                        <div class="md-right">
                            <div class="md-half-circle"></div>
                        </div>
                    </div>
                </div>
            </md-progress-circular>
            <h4>
                    To do app is loading...
            </h4>
        </div>
    </app>
    <script>
        System.paths = {
            'angular2/*': 'quickstart/angular2/*.js',
            'rtts_assert/*': 'quickstart/rtts_assert/*.js',
            'app/*': 'app/*.js'
        };
        System.import('app/App');
    </script>
</body>
</html>


Здесь следует обратить внимание на три момента:

Прежде всего мы подключили файл es6-shim, в нем заботливо собрано всё вышеперечисленное, что нам нужно для запуска приложения.

Далее обратим внимание на элемент app. Это и будет наш главный компонент приложения. Сейчас в нем содержится просто разметка со спиннером и надписью To do app is loading… она будет показываться пока ангуляр не загрузит класс компонента и не заменит эту разметку на его template.

В самом низу мы использовали библиотеку system.js, она реализует систему загрузки модулей ES6. Сначала при помощи System.paths мы настроили пути к .js файлам, затем с помощью System.import загрузили файл с компонентом app, а он, в свою очередь, уже и потянет за собой все нужные библиотеки и компоненты.

Теперь создадим папку app и положим в неё файл App.js:

import {Component, Template, bootstrap, Foreach} from 'angular2/angular2';
import {TodoStore} from 'app/TodoStore';
import {ItemEditor} from 'app/ItemEditor';

@Component({
    selector: 'app',
    componentServices: [
	  TodoStore
    ]
})
@Template({
    url: 'app/todo.html',
    directives: [Foreach, ItemEditor]
})
class App {
    constructor(store:TodoStore) {
        this.store=store;
    }
}

bootstrap(App);


Сначала мы импортируем классы Component, Template, Foreach из angular2.js, оттуда же импортируем функцию bootstrap, уже знакомую тем, кто в версии 1.x не использует директиву ng-app, она инициализирует главный компонент приложения, следом мы импортируем классы TodoStore из app/todoStore.js (это будет сервис, отвечающий за работу со списком задач и его хранение в localStorage браузера) и ItemEditor из app/item-editor.js (это будет компонент — директива, отображающий элемент списка). Мы их пока не написали, поэтому рассмотрим их позже.

Далее мы создаём класс App, ему в конструктор при помощи инъектора передаётся объект класса TodoStore, который мы присваиваем свойству store.

При объявлении класса мы использовали аннотации Component и Template из angular2.js:
Component – аннотация, которая и делает класс компонентом. Свойство selector — это селектор, позволяющий обнаружить элемент в разметке шаблона, у нас это элемент app. Свойство componentServices – это список классов для инъектора.

Template – помогает указать для компонента шаблон. Свойство url указывает путь, где будет находиться шаблон, свойство directives указывает список директив, которые используются в разметке этого шаблона.

В конце файла мы используем функцию bootstrap, чтобы инициализировать наш главный компонент.

Давайте теперь создадим файл app/TodoStore.js:

export class TodoStore {
    constructor() {
        this.load();
    }
    save() {
        window.localStorage['todoItems']=JSON.stringify(this.items);
    }
    addItem(name, checked) {
        this.items.push(new Item(name,checked));
    }
    clear() {
        this.items.length=0;
    }
    load() {
        this.items=[];
        let itemsStr=window.localStorage['todoItems'];
        if(itemsStr) {
            JSON.parse(itemsStr).forEach((e) => {
                this.addItem(e.name, e.checked);
            });
        }
    }
}


class Item {
    constructor (name, checked){
        this.name = name;
        this.checked=checked || false;
    }
    toggleCheck() {
        this.checked=!this.checked;
    }
}

У класса TodoStore есть методы save(), load(), clear(), и addItem(name, checked).

Сам список задач будет храниться в свойстве items. Метод save() сохраняет значение свойства items в localStorage. Метод clear() очищает свойство items. Метод load() загружает из localStorage все элементы списка и добавляет их в items с помощью метода addItem. Метод addItem(name, checked) принимает имя пункта списка, создаёт новый объект Item и добавляет его в Items.

Следом идёт объявление класса Item, конструктор принимает name — имя пункта списка и checked — отмечен ли он как выполненный. Ещё у класса есть метод toggleCheck(), который меняет значение checked на противоположное.

Далее создаём файл app/todo.html с шаблоном главного компонента:

<style>
    @import "../bower_components/angular-material/angular-material.css";

    .md-primary {
        background-color: #039be5;
        color: white;
    }

    md-toolbar {
        background-color: #CFD8DC;
    }

    md-input-container {
        padding-bottom: 0;
    }
</style>
<div flex layout="column" layout-fill layout-margin>
    <md-toolbar class="md-primary">
        <h2 class="md-toolbar-tools">
            <span>To do list</span>
        </h2>
    </md-toolbar>
    <md-content layout="row" layout-align="center start" flex>
        <div flex="50" flex-md="80" flex-sm="100">
            <div layout="row" layout-margin flex>
                <button flex class="md-button md-primary md-raised md-default-theme" (click)="store.save()">Save</button>
                <button flex class="md-button md-primary md-raised md-default-theme" (click)="store.load()">Load</button>
                <button flex class="md-button md-primary md-raised md-default-theme" (click)="store.clear()">Clear</button>
            </div>
            <div layout="row" layout-margin flex>
                <md-input-container class="md-input-has-value" flex="60">
                    <input #newitem class="md-input" placeholder="New to do item" />
                </md-input-container>
                <button flex class="md-button md-primary md-raised md-default-theme" (click)="store.addItem(newitem.value)">Add new item</button>
            </div>
            <md-list>
                <md-item *foreach="#item in store.items">
                    <md-item-content>
                        <item-editor [item]="item"></item-editor>
                    </md-item-content>
                </md-item>
            </md-list>
        </div>
    </md-content>
</div>

Здесь у нас есть три кнопки, которые вызывают методы хранилища store.save(), store.load() и store.clear(). Мы привязываемся к событию click каждой кнопки с помощью атрибута (click). В нынешней версии ангуляра порой довольно трудно с первого взгляда отличить в разметке, какой атрибут используется для привязки к событию, а какой для привязки данных, теперь же всё будет видно сразу, круглые скобки () нужны, чтобы реагировать на события элемента или компонента, а атрибут в квадратных скобках [] осуществляет привязку к данным, подразумевается, что значение атрибута — это выражение, которое будет вычислено, а его результат будет присвоен атрибуту элемента, если атрибут указан вообще без всяких скобок — то подразумевается, что в нём просто текстовое значение.

Далее обратим внимание на input с атрибутом #newitem таким образом мы теперь можем задавать элементу имя, по которому он будет нам доступен, как в событии click кнопки ниже, где мы берём значение input'а — newitem.value и передаём его в store.addItem().

Следом идёт список задач, который мы вывели с помощью новой директивы *foreach (это замена ng-repeat), здесь, как и в input'е выше, мы написали #item, чтобы обращаться далее к каждому элементу списка по имени item.

Каждый элемент списка мы собираемся выводить при помощи директивы item-editor, которой мы привязываем элемент списка с помощью атрибута [item].

Теперь создадим файл app/ItemEditor.js с компонентом ItemEditor, который будет отвечать за отображение элементов списка.

import {Component, Template} from 'angular2/angular2';

@Component({
    selector: 'item-editor',
    bind: {
        'item': 'item'
    }
})
@Template({
    inline: `
        <style>
        
        @import "../bower_components/angular-material/angular-material.css";
        md-checkbox.md-checked .md-icon {
            background-color: #039be5;
            color: white;
        }
        </style>
        <md-checkbox [class.md-checked]="item.checked" (click)="item.toggleCheck()">
        <div class="md-label">
            <div class="md-container">
                <div class="md-icon"></div>
            </div>
            <span>
                {{item.name}}
            </span>
        </div>
        </md-checkbox>
        ` 
})
export class ItemEditor {

}


Здесь в @Component мы указали селектор 'item-editor', это элемент, который используется в *foreach в todo.html. Следом указано свойство bind, оно указывает, что нужно привязать значение атрибута item к свойству item класса компонента(что-то вроде bindToController).

В Template на этот раз вместо url для примера указано свойство inline, оно служит для указания текста шаблона прямо в коде. Это снижает количество требуемых http запросов, поэтому после выхода Angular 2 скорее всего появится кокой-нибудь плагин для Gulp, который будет менять url на inline, на замену нынешнему gulp-angular-templatecache.

В самом шаблоне можно увидеть атрибут [class.md-checked] — это лаконичная замена ng-class. А ниже выводится имя элемента списка с помощью уже ставшего родным синтаксиса с фигурными скобками {{item.name}}.

Вот и всё, теперь можно запустить проект(проверял только в Хроме) и посмотреть, как работает будущий Angular 2.0.

Как мы видим, разработчики полностью переосмыслили концепцию Angular.js и нас теперь ждёт абсолютно новый фреймворк с новым, более лаконичным синтаксисом. Благодаря абсолютно новой архитектуре, созданной с расчётом на большие приложения, производительность рендеринга, главный бич версий 1.x, возрастает во много раз (наглядное сравнение можно посмотреть в конце доклада Дейва Смита Angular + React = Speed). Возможность использовать типизацию открывает перспективы развития IDE для продвинутой поддержки дополнения кода и статического анализа (как минимум, Microsoft заявляет поддержку Angular в Visual Studio одним из приоритетов). А новшества ES6 сделают разработку ещё быстрее и приятнее.

Это практически и всё, что мне удалось узнать об Angular 2.0 на сегодня, будем дальше следить за новостями, а пока вот несколько и интересных ссылок по теме:

Канал ng-conf на YouTube с массой интересных докладов
Официальный сайт Angular 2.0
Проект Angular 2 на GitHub
Теги:
Хабы:
+21
Комментарии53

Публикации

Изменить настройки темы

Истории

Работа

Ближайшие события