В прошлом году я написал сообщение о том, как я сделал миксин Ember, который позволял компонентам или представлениям Ember знать, вошел ли их элемент DOM во вьюпорт или покинул его. Если вы не знакомы с API getBoundingClientRect или с подходом в целом (для определения того, находится ли элемент в области просмотра), сначала прочтите этот пост!

На этот раз я хочу рассказать о том, как я улучшил исходный Mixin, чтобы использовать API requestAnimationFrame для повышения производительности почти со скоростью 60 кадров в секунду, а также пройти процесс создания простого тлеющего угля. -cli addon ». Поскольку некоторые браузеры (в основном IE) не поддерживают rAF, мы также настроим автоматический возврат к использованию метода цикла выполнения Ember, который я использовал в своем предыдущем посте.

Давайте начнем!

Демо-приложение

Я сделал простое демонстрационное приложение, чтобы продемонстрировать, как вы можете использовать Mixin. Цель этого дополнения заключалась в том, чтобы позволить вам легко стилизовать или делать что-то с компонентами / представлениями, когда они входят или выходят из области просмотра. Например, вы можете легко использовать этот миксин для создания ленивого загрузчика изображений или даже для запуска анимации. Используя этот Mixin, вам не нужно приносить плагин jQuery, и вместо этого вы можете полагаться на высокопроизводительный аддон ember-cli.

Установка аддона

Если вы используете ember-cli и хотите использовать аддон, вы можете установить его с помощью:

$ ember install ember-in-viewport

Исходный код аддона доступен по адресу dockyard / ember-in-viewport.



Создание вашего первого аддона ember-cli

Я собираюсь пройти через этот пост, как если бы я создавал аддон ember-in-viewport, поэтому я буду использовать это имя с этого момента.

С помощью ember-cli для создания нового дополнения достаточно одной команды:

$ ember addon ember-in-viewport

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

Обновление манифестов

Package.json - это манифест для вашего аддона ember-cli, который многое делает с npm. Поскольку это довольно просто, я не буду вдаваться в подробности здесь, но вы захотите обновить имя, описание, репозиторий , автор имя и ключевые слова в соответствии с вашим дополнением. Если вас вообще интересуют оценки в Ember Observer, вы должны убедиться, что они заполнены правильно, потому что они действительно влияют на результаты! Они также помогают найти ваш аддон на npm, так что не помешает заполнить их с самого начала.

Для этого дополнения, поскольку мы не используем ember-data, мы собираемся удалить эту строку в package.json, а также bower.json.

Добавление конфигурации ember-try

Ember-try - это замечательный аддон ember-cli от @katiegengler, который помогает вам тестировать несколько зависимостей bower, таких как ember и ember-data. Это означает, что вы сможете протестировать свой аддон, чтобы убедиться, что он работает в других версиях, что приятно как автору аддона! Для ember-in-viewport мы тестируем ember 1.11.1, релизную, бета-версию и канареечные каналы.

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

Переписывание миксина в окне просмотра

Mixin по-прежнему использует тот же метод для определения, находится ли элемент DOM в области просмотра, используя getBoundingClientRect и innerHeight и innerWidth окна.

Во-первых, давайте создадим новый миксин с помощью ember-cli:

$ ember g mixin in-viewport

Это создает соответствующие файлы внутри / addon, который является основной папкой для логики вашего аддона. Эта папка не будет объединена с деревом приложения-потребителя Ember (в отличие от папки / app). Для этого аддона мы хотим, чтобы наши пользователи импортировали миксин непосредственно из самого аддона, поэтому мы удалим папку, созданную внутри / app, и обновим сгенерированные тесты, чтобы импортировать нужный файл. .

Импорт модулей и утилит

Внутри addons / mixins / in-viewport.js мы импортируем модули, которые требуются миксину. Модули canUseDOM и canUseRAF представляют собой простые служебные файлы, которые помогают нам определить, доступна ли DOM (это особенно важно для запуска тестов PhantomJS и FastBoot / рендеринга на стороне сервера), а также поддерживает ли браузер пользователя функцию requestAnimationFrame API.

Чтобы создать новый служебный файл:

$ ember g util can-use-dom

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

Обновление логики "Находится в области просмотра"

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

С добавлением опции допуска пользователи аддона могут снизить точность проверки. Если установлено значение 0, Mixin рассматривает элемент внутри области просмотра только тогда, когда он полностью виден внутри области просмотра.

Настройка переменных класса

Если у вас не было возможности использовать функции ES2015, сейчас хорошее время для изучения, поскольку ember-cli-babel уже некоторое время поставляется с ember-cli по умолчанию. Здесь мы деструктурируем определенные методы из Ember, а также настраиваем массив слушателей, которые мы хотим зарегистрировать. Я также объявляю изменяемую переменную rAFIDS с помощью let - я буду использовать этот объект для хранения идентификатора, возвращаемого функцией requestAnimationFrame, чтобы мы могли отменить его позже.

Интересно отметить, что эти переменные фактически используются всеми экземплярами Mixin. Это означает, что если мы сохранили идентификатор rAF в этой переменной, он будет перезаписан другими экземплярами компонентов, за которыми следит Mixin. Поэтому вместо этого мы будем хранить каждый идентификатор rAF как ключ (идентификатор элемента для компонента) внутри объекта. Подробнее об этом позже.

Начальное состояние

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

Здесь мы также собираемся использовать нашу служебную функцию canUseRAF, чтобы сообщить Mixin, следует ли использовать requestAnimationFrame или вернуться к циклу выполнения Ember.

Вычисляемые свойства только для чтения

Для удобства мы добавим вычисляемое свойство «viewportExited» (например, «viewportEntered»), которое могут использовать пользователи нашего аддона. Настроить это просто:

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

Настройка элемента DOM, отображаемого компонентом

Когда элемент DOM вставлен в DOM, нам нужно будет настроить несколько вещей:

  1. Первоначальная проверка рендеринга, чтобы увидеть, находится ли элемент сразу в поле зрения
  2. Настройка наблюдателя, если мы не следим за элементом
  3. Вызов рекурсивного метода requestAnimationFrame
  4. Настройка и удаление слушателей событий, если мы шпионим за элементом

Проверка, находится ли элемент DOM сразу в поле зрения

После того, как элемент был отрисован в DOM, мы хотим немедленно проверить, видим ли он. Это вызывает метод _setViewportEntered в очереди afterRender цикла выполнения Ember.

Отмена привязки слушателей после входа в область просмотра

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

Здесь мы программно добавляем наблюдателя в свойство viewportEntered, если для параметра viewportSpy было установлено значение false нашим пользователем дополнения. Сам наблюдатель мало что делает - он отвязывает слушателей, а затем удаляется.

Настройка слушателей событий

Давайте посмотрим на привязку наших прослушивателей событий, прежде чем мы рассмотрим _setViewportEntered, основной метод миксина. Мы будем использовать массив слушателей, который мы объявили ранее в верхней части файла, и привязать событие к соответствующему контексту (window или document), например:

Обратите внимание, что на самом деле мы можем передать elementId компонента (атрибут id, который отображается в DOM) событию, что позволит нам отвязать прослушиватель только для этого конкретного элемента. Если бы мы этого не сделали, все слушатели были бы освобождены, когда первый элемент DOM входит в область просмотра, чего мы не ожидали.

Обработка события

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

Связывание слушателей

Когда мы в конечном итоге уничтожаем Компонент, мы хотим убедиться, что убираем за собой. Придется удалить как прослушиватели событий, так и рекурсивный вызов requestAnimationFrame:

Если вы помните, функция requestAnimationFrame возвращает идентификатор, который однозначно идентифицирует запись в списке обратного вызова. Мы можем передать это в cancelAnimationFrame, чтобы отменить бесконечно рекурсивный вызов основного метода. Поскольку мы регистрируем DOM elementId компонента в качестве ключа в объекте rAFIDS, мы можем удалить конкретный вызов rAF для этого единственного компонента. Я заключил вызов cAF в Ember.run.next, чтобы избежать состояния гонки, препятствующего правильной отмене рекурсии rAF, которая случается время от времени.

Обновление свойства viewportEntered

Давайте посмотрим на основной метод, отвечающий за установку свойства ‘viewportEntered’. Этот метод выполняет две основные задачи:

  1. Установите для viewportEntered значение true или false
  2. Запустить следующий шаг requestAnimationFrame

В качестве простой оптимизации мы можем кэшировать выбранный элемент DOM внутри объекта как $ viewportCachedEl, чтобы нам не приходилось каждый раз вызывать дорогостоящий метод выбора узла DOM. Затем мы передаем свойства элемента Component в служебную программу, которую мы определили ранее, и устанавливаем для свойства viewportEntered значение true или false.

Если requestAnimationFrame включен, мы снова вызываем метод внутри метода rAF после привязки его к правильному контексту. Как и Function.prototype.bind (), это создает новую функцию, которая при вызове имеет ключевое слово this, установленное на правильное значение (вместе с любыми аргументами). С этим первым вызовом после того, как элемент вставлен в DOM, запускается бесконечно рекурсивный цикл, который закончится только тогда, когда мы его отменим.

Следовательно, нам не нужно настраивать прослушиватели событий, когда включен rAF. Вот и все, что касается Mixin!

Резюме

По сути, Mixin делает одно из двух, когда реализуется компонентом или представлением:

  1. Если rAF включен, он запускает бесконечно рекурсивный вызов основного метода со скоростью около 60 кадров в секунду (или независимо от частоты обновления монитора пользователя) без использования прослушивателей событий. Затем это отменяется, когда компонент уничтожается или если для параметра viewportSpy установлено значение false, а компонент уже один раз вошел в область просмотра.
  2. В противном случае Mixin настраивает прослушиватели событий на уникальном элементе DOM компонента и запускает основной метод всякий раз, когда пользователь запускает одно из трех событий (прокрутка, изменение размера и касание). Опять же, прослушиватели событий удаляются при уничтожении и если для параметра viewportSpy установлено значение false.

Раскрытие вашего аддона в сообществе Ember

Теперь, когда мы закончили с основной логикой аддона и написали тесты (тема для другого поста!), Мы готовы выпустить наш аддон в мир! Обычно я использую git flow для управления своими репозиториями, и он также помогает в процессе выпуска с помощью git flow release.

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

После того, как ваши изменения будут снова объединены в master, вы можете опубликовать свой аддон на npm:

$ npm publish

Поздравляю! Вы написали свой первый аддон… Теперь вы можете следить за рейтингом своего аддона в Ember Observer.

Спасибо за чтение!

Это был довольно длинный пост, надеюсь, вы кое-что узнали. Если вы хотите задать какие-либо вопросы, отправьте мне твит.

Некоторые из вас, наверное, знают, что я недавно присоединился к DockYard. Если вы ищете экспертов Ember для пополнения штата, работы над новым или уже существующим проектом, свяжитесь с нами!

До скорого,

Лорен