27.12.2017

Создание ViewModel и Observable-значений — Knockout.js

Knockout построен на основе трех основных возможностей:

  • Observable-переменные и отслеживание зависимостей
  • Декларативные биндинги
  • Шаблонизация

На этой странице, вы узнаете о первой из трех. Но перед этим, давайте изучим паттерн MVVM и концепцию view model.

Модели MVVM и View Model

Model-View-View Model (MVVM) это шаблон проектирования для построения пользовательских интерфейсов.
В нем описывается, как вы можете с легкостью хранить потенциально сложный UI разделяя его на три части:

  • Модель (model): хранимые данные вашего приложения. Эти данные представляют объекты и операции в вашем бизнес-домене (например, банковские счета, которые могут выполнять переводы средств) и не зависимы от какого-либа UI.
    При использовании KO, вы оыбчно делаете Ajax запросы к какому-то коду на серверной стороне, для чтения и записи этих данных, хранимых в модели.
  • Модель представления (view model): чистый код представления данных и операции над UI. Например, если вы реализуете редактор списков, ваша view model будет объектом,
    содержащим список элементов, и показывать методы для добавления и удаления элеиентов списка.Обратите внимание, что это не сам UI: он не содержит каких-либо концепций кнопок или отображаемых стилей.
    Это не сохранившаясь модель данных — она содержит несохраненные данные, с которыми работает пользователь.
    При использовании KO, ваши view model это чистые JavaScript объекты, которые не содержат знаний об HTML.
    Хранение view model абстрактынми при данном способе позволяют сохранять простую структуру, таким образом, вы можете управлять более сложными поведениями, не теряясь в коде.
  • Представление (view): видимый, интерактивный UI представляющий состояние view model.
    Он отображает информацию из view model, отправляет команды во view model (например, когда пользователь щелкает по кнопке),
    и обновляет интерфейс, если соответствующий ему элемент view model изменился.При использовании KO, ваш view это просто HTML документ с декларативными биндингами для связи его с view model.
    Альтернативно, вы можете использовать шаблоны, которые генерируют HTML, используя данные из вашей view model.

Для создания view model с KO, просто объявите любой JavaScript объект. Например,

var myViewModel = {
    personName: 'Bob',
    personAge: 123
};

Затем вы можете создать примитивное представление (view) данной модели представления(view model) используя декларативные биндинги. Например, следующая разметка отобразит значение свойства personName:

The name is <span data-bind="text: personName"></span>

Активация Knockout

Атрибут data-bind не является нативным в HTML, хотя он прекрасно подходит (он строго соответствует HTML 5, и не вызывает проблем в HTML 4, хотя валидатор
и скажет что это неизвестный атрибут). Но поскольку браузер не знает, что это означает, вам нужно активировать Knockout, чтобы он заработал.

Для активации Knockout, добавьте следующую строчку в блок <script>:

ko.applyBindings(myViewModel);

Можно разместит блок со скриптом либо в нижней части HTML документа,
или можно добавить в верхней части сайта, и обернуть контент в обработчик DOM-ready, вроде функции $ в jQuery.

Готово! Теперь, представление будет выглядеть так, как если бы вы написали следующий HTML:

The name is <span>Bob</span>

В случае, если вам интересно, что делают параметры функции ko.applyBindings, то:

  • Первый параметр говорит какой объект модели представления (view model) вы хотите использовать для включения декларативных биндингов на странице
  • (Опционально). Можно указать второй параметр, для определения, какая часть документа будет использоваться для поиска data-bind атрибутов.
    Например, ko.applyBindings(myViewModel, document.getElementById(‘someElementId’)).
    Данная конструкция ограничивает применение биндингов до элемента с ID someElementId и его потомков,
    что полезно, если хотите сделать множество моделей представления и связать каждую с разными частями страницы.

Очень легко, правда.

Observable

ОК, вы увидели как создать базовую модель представления (view model) и как отобразить одно из её свойств используя биндинг.
Но одной из ключевых фишек KO является автоматическое обновление вашего UI при изменении модели представления.
Как KO узнает в какой момент часть моей модели изменяется? Ответ: нужно объявить свойство модели с типом observable,
потому что это такие специальные JavaScript объекты, которые могут уведомлять подписчиков об изменениях, и могут автоматически определять зависимости.

Например, перепишите предыдущий пример объекта модели представления следующим образом:

var myViewModel = {
    personName: ko.observable('Bob'),
    personAge: ko.observable(123)
};

Вам не нужно вносить корректировки в представление — ведь здесь работает тот же data-bind синтаксис.
Разница лишь в том, что теперь он может отслеживать изменения, и когда они происходят, то представление обновляется автоматически.

Чтение и запись observable-переменных

Не все браузеры поддерживают геттеры и сеттеры в JavaScript (* кашель * IE *кашель *), так что для совместимости, объекты ko.observable в действительности являются функциями.

  • Для чтения текущего значения observable переменной, вы вызываете её, как функцию без параметров. В этом примере, myViewModel.personName() вернет значение ‘Bob’,
    и myViewModel.personAge() вернет 123.
  • Для записи нового значения, вызовите переменную, как функцию с передачей нового значения в качестве параметра.
    Например, вызов myViewModel.personName(‘Вася’) изменит значение имени человека на ‘Вася’.
  • Для записи значений во множество observable свойств объекта модели, можно воспользоваться цепочкой методов.
    Например, myViewModel.personName(‘Вася’).personAge(50) изменит имя на ‘Вася’ и возраст на 50.

Весь смысл observable-переменных заключается в возможности наблюдать за ними, например, другие участки кода могут сказать, что хотят получать уведомления об изменениях.
Это то, что делает множество встроенных в KO биндингов внутри самой библиотеки. Итак, когда вы пишете data-bind=»text: personName», биндинг text регистрирует себя в качестве получателя уведомлений об изменениях personName (предполагается, что переменная имеет тип observable, как сейчас).

Когда вы изменяете значение имени на ‘Вася’ вызывая myViewModel.personName(‘Вася’), биндинг text автоматически обновит текстовое
содержимое связанного с биндингом DOM элемента. Это то, как происходит автоматическое распространение изменений из модели представления в представление.

Прямая подписка на изменение observable

Обычно нет нужды напрямую подписываться на изменения переменной, так что новичкам следует пропустить эту секцию.

Для продвинутых пользователей, если хотите зарегистрировать свою собственную подписку для уведомления об изменении observable-переменной, то можете вызывать её функцию subscribe. Например:

myViewModel.personName.subscribe(function(newValue) {
    alert("Имя данного пользователя " + newValue);
});

Функция subscribe — это то, как работает множество частей внутри библиотеки KO.
Чаще всего вам не понадобится это использовать, потому что встроенные биндинги и система шаблонизации сами управляют подписками.

Функция subscribe принимает три параметра: callback — это функция, вызываемая при появлении уведомления,
target (опционально) определяет значение this в callback функции, и параметр event (опционально; по-умолчанию «change») — имя события для которого получать уведомления.

Вы можете так же прекратить подписку, если это требуется: сначала нужно получить возвращаемое значение подписки в виде переменной, затем можно вызывать её функцию dispose, например:

var subscription = myViewModel.personName.subscribe(function(newValue) { /* какие-то действия */ });
// ...затем позже...
subscription.dispose(); // Мне больше не нужны уведомления

Если вы хотите получать уведомление о значении observable-переменной до того, как произойдет изменение, то можно подписаться на событие beforeChange. Например:

myViewModel.personName.subscribe(function(oldValue) {
    alert("Предыдущее имя человека было " + oldValue);
}, null, "beforeChange");

Примечание: Knockout не гарантирует, что события beforeChange и change будут происходить парами, поскольку остальные участки вашего кода могут производить эти события в индивидуальном порядке.
Если нужно отслеживать предыдущее значение observable-переменной, то использование подписки и захват её значения — это то, что доктор прописал.

Заставляем observable всегда уведомлять подписчиков

При написании observable-переменных содержащих примитивные значения (число, строка, булевое значение, или null),
то зависимые от observable-переменной функции уведомляются лишь тогда, когда значение в действительности изменилось.
Однако, можно использовать встроенный экстендер уведомлений чтобы обеспечить подписчиков уведомлениями
каждый раз при записи значения, даже если значение такое же. Применять экстендеры к observable-переменным можно таким образом:

myViewModel.personName.extend({ notify: 'always' });

Задержка и/или подавление уведомлений об изменении

В обычное время, observable-переменные уведомляют подписчиков мгновенно, как только изменилось значение.
Но если observable изменяется несколько раз или запускает дорогостоящие(касательно производительности) обновления, то можно улучшить производительность,
ограничив, или сделав задержку в создании уведомления от observable-переменной при её изменении. Это достигается с помощью экстендера rateLimit например так:

// Обеспечиваем создание уведомлений не чаще чем раз за 50-миллисекундный период
myViewModel.personName.extend({ rateLimit: 50 });

Эксклюзивно для сайта skv1991.ru

Перепечатка и копирование строго запрещены.

Оригинал страницы

Опубликовано: 27/12/2017

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *