Статьи

Анимационный нокаут

Knockout.js не является библиотекой анимации. Все автоматические обновления Knockout.js применяются немедленно при изменении базовых данных. Чтобы оживить любое из его изменений, нам нужно покопаться во внутренностях Knockout.js и вручную создать анимированные переходы, используя другую инфраструктуру JavaScript, такую ​​как jQuery или MooTools. Этот урок придерживается процедур анимации jQuery, но представленные концепции применимы и к другим библиотекам анимации.


Для этого урока мы вернемся к упрощенной версии нашего примера корзины покупок. Создайте новый файл HTML со следующим содержимым. Мы не будем делать никаких запросов AJAX, поэтому не стесняйтесь размещать их в любом месте на вашем компьютере. Однако мы будем использовать подпрограммы анимации jQuery, поэтому обязательно добавьте ссылку на вашу копию библиотеки jQuery.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<html lang=’en’>
<head>
  <title>Animating Knockout.js</title>
  <meta charset=’utf-8′ />
  <link rel=’stylesheet’ href=’style.css’ />
</head>
<body>
  <h2>
  <table>
    <thead><tr>
      <th>Product</th>
      <th>Price</th>
      <th></th>
    </tr></thead>
    <tbody data-bind=’foreach: items’>
      <tr>
        <td data-bind=’text: name’></td>
        <td data-bind=’text: price’></td>
        <td><button data-bind=’click: $root.removeProduct’>Remove</button></td>
      </tr>
    </tbody>
  </table>
 
  <button data-bind=’click: addProduct’>Add Beer</button>
 
  <script src=’knockout-2.1.0.js’></script>
  <script src=’jquery-1.7.2.js’></script>
  <script>
    function Product(name, price, tags, discount, details) {
      this.name = ko.observable(name);
      this.price = ko.observable(price);
    }
    function ShoppingCart() {
      var self = this;
      this.instructions = ko.observable(«»);
      this.hasInstructions = ko.observable(false);
 
      this.items = ko.observableArray([
        new Product(«Beer», 10.99),
        new Product(«Brats», 7.99),
        new Product(«Buns», 1.49)
      ]);
 
      this.addProduct = function() {
        this.items.push(new Product(«More Beer», 10.99));
      };
 
      this.removeProduct = function(product) {
        self.items.destroy(product);
      };
 
    };
    ko.applyBindings(new ShoppingCart());
  </script>
</body>
</html>

Надеюсь, это все обзор на данный момент. У нас есть наблюдаемый массив, содержащий набор продуктов, привязку foreach , отображающую каждый из них, и кнопку для добавления дополнительных товаров в корзину.


Knockout.js — это мощная библиотека пользовательского интерфейса, но как только вы объедините ее с возможностями анимации таких фреймворков, как jQuery или MooTools, вы будете готовы создавать действительно потрясающие пользовательские интерфейсы с минимальной разметкой. Сначала мы рассмотрим анимированные списки, а затем в следующем разделе представлен более общий способ анимации компонентов представления.

Привязка foreach имеет два обратных вызова с именами beforeRemove и afterAdd. Эти функции выполняются перед удалением элемента из списка или после его добавления в список, соответственно. Это дает нам возможность анимировать каждый элемент до того, как Knockout.js манипулирует DOM. Добавьте обратные вызовы к элементу <tbody> следующим образом:

1
2
3
<tbody data-bind=’foreach: {data: items,
     beforeRemove: hideProduct,
     afterAdd: showProduct}’>

Вместо свойства наша привязка foreach теперь принимает литерал объекта в качестве параметра. Свойство data параметра указывает на массив, который вы хотите отобразить, а свойства beforeRemove и afterAdd указывают на нужные функции обратного вызова. Далее, мы должны определить эти обратные вызовы в ShoppingCart ViewModel:

01
02
03
04
05
06
07
08
09
10
11
this.showProduct = function(element) {
  if (element.nodeType === 1) {
    $(element).hide().fadeIn();
  }
};
 
this.hideProduct = function(element) {
  if (element.nodeType === 1) {
   $(element).fadeOut(function() { $(element).remove(); });
  }
};

showProduct() вызов showProduct() использует jQuery для постепенного появления новых элементов списка, а hideProduct() вызов hideProduct() их, а затем удаляет из DOM. Обе функции принимают затронутый элемент DOM в качестве первого параметра (в данном случае это элемент <tr>). Условные операторы гарантируют, что мы работаем с полноценным элементом, а не простым текстовым узлом.

Конечным результатом должны быть элементы списка, которые плавно переходят в список и из него. Конечно, вы можете свободно использовать любые другие переходы jQuery или выполнять пользовательскую постобработку в любом из обратных вызовов.


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

Пользовательские привязки работают так же, как привязки по умолчанию в Knockout.js. Например, рассмотрим следующие поля формы:

01
02
03
04
05
06
07
08
09
10
11
<div>
  <p>
    <input data-bind=’checked: hasInstructions’
           type=’checkbox’ />
    Requires special handling instructions
  </p>
<div>
 
<textarea data-bind=’visible: hasInstructions,
                         value: instructions’>
</textarea>

Флажок действует как переключатель для <textarea> , но поскольку мы используем visible привязку, Knockout.js внезапно добавляет или удаляет ее из DOM. Чтобы обеспечить плавный переход для <textarea> , мы создадим пользовательскую привязку с именем visibleFade:

1
2
<textarea data-bind=’visibleFade: hasInstructions,
                           value: instructions’>

Конечно, это не будет работать, пока мы не добавим пользовательскую привязку в Knockout.js. Мы можем сделать это, добавив объект, определяющий привязку к ko.bindingHandlers как показано в следующем примере кода. Это также происходит там, где определены все встроенные привязки.

01
02
03
04
05
06
07
08
09
10
ko.bindingHandlers.visibleFade = {
  init: function(element, valueAccessor) {
    var value = valueAccessor();
    $(element).toggle(value());
  },
  update: function(element, valueAccessor) {
    var value = valueAccessor();
    value() ?
  }
}

Свойство init определяет функцию, которую нужно вызвать, когда Knockout.js впервые обнаруживает привязку. Этот обратный вызов должен определять начальное состояние для компонента представления и выполнять необходимые действия по настройке (например, регистрация прослушивателей событий). Для visibleFade все, что нам нужно сделать, это показать или скрыть элемент в зависимости от состояния ViewModel. Мы реализовали это используя метод toggle () jQuery .

Параметр element — это связанный элемент DOM, а valueAccessor — это функция, которая будет возвращать рассматриваемое свойство ViewModel. В нашем примере элемент ссылается на <textarea> , а valueAccessor () возвращает ссылку на наблюдаемую hasInstructions.

Свойство update определяет функцию, которая должна выполняться всякий раз, когда изменяется связанная наблюдаемая, и наш обратный вызов использует значение hasInstructions для hasInstructions <textarea> в соответствующем направлении. Помните, что вам нужно вызывать наблюдаемое, чтобы получить его текущее значение (то есть значение () , а не значение). Однако если бы hasInstructions было обычным свойством JavaScript вместо наблюдаемого, это было бы не так.


В этом уроке мы обнаружили два метода анимации компонентов представления Knockout.js. Во-первых, мы добавили методы обратного вызова в привязку foreach , что позволяет делегировать добавление и удаление элементов пользовательской функции. Это дало нам возможность интегрировать анимированные переходы jQuery в наш шаблон Knockout.js. Затем мы исследовали пользовательские привязки как средство для анимации произвольных элементов.

В этом уроке представлен общий пример использования пользовательских привязок, но они ни в коем случае не ограничиваются анимацией компонентов пользовательского интерфейса. Настраиваемые привязки также можно использовать для фильтрации данных по мере их сбора, прослушивания пользовательских событий или создания многократно используемых виджетов, таких как сетки и выгружаемый контент. Если вы можете инкапсулировать поведение в функции init и обновления, вы можете превратить его в пользовательскую привязку.


Эта серия охватывала подавляющее большинство нокаутов.

Knockout.js — это чистая библиотека JavaScript, которая позволяет невероятно легко создавать динамические, ориентированные на данные пользовательские интерфейсы. Мы узнали, как выставлять свойства ViewModel с помощью наблюдаемых, связывать элементы HTML с этими наблюдаемыми, управлять вводом пользователя с помощью интерактивных привязок, экспортировать эти данные в сценарий на стороне сервера и анимировать компоненты с помощью пользовательских привязок. Надеюсь, вы более чем готовы перенести эти знания в свои реальные веб-приложения.

Эта серия статей охватывала подавляющее большинство API-интерфейса Knockout.js, но остается еще ряд нюансов, которые нужно обнаружить. К этим темам относятся: пользовательские привязки для типов агрегированных данных, расширитель throttle для асинхронной оценки вычисляемых наблюдаемых и ручная подписка на события наблюдаемой. Тем не менее, все это сложные темы, которые не должны быть необходимы для типичного веб-приложения. Тем не менее, Knockout.js предоставляет множество возможностей расширения для вас, чтобы исследовать.

Если вы предпочитаете перечитать эту сессию в этой книге «> Форма электронной книги, обязательно посетите веб-сайт Syncfusion . Кроме того, они предлагают множество бесплатных электронных книг, как эта!

Этот урок представляет собой главу от Knockout Succinctly , бесплатной электронной книги от команды Syncfusion .