Создание набора инструментов для поддержки мобильного приложения Onefill заставило нас взглянуть и изучить некоторые новые аспекты использования JavaScript. В этой статье основное внимание уделяется одной из основных задач, которыми мы занимаемся: заполнению форм.

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

В этом посте я остановлюсь на двух основных этапах этого процесса:

  1. Нахождение элемента для заполнения; и
  2. Вставка данных в этот элемент.

Шаг 1. Поиск элемента

Основная проблема, которую мы решаем, - как интерпретировать все формы, с которыми вы можете столкнуться в Интернете, и понять их структуру и семантику отдельных элементов. Это поле "имя" должно быть для вашей фамилии или вашего полного имени? Ожидается ли в этом поле адреса ваш полный адрес проживания или только его первая строка?

Чтобы всегда делать это правильно, мы создали расширение Chrome, которое помогает нашему движку идентифицировать элементы, находить их селекторы и создавать сопоставления между нашими элементами данных и структурой формы.

Во-первых, чтобы указать на любой элемент на странице, нам нужно знать кратчайший путь (или селектор) к элементу, который мы пытаемся найти. Затем мы можем прослушать событие щелчка на странице.

И поскольку мы стремимся к интеграции с сотнями и тысячами различных интернет-магазинов, мы решили держаться подальше от использования каких-либо вспомогательных библиотек или фреймворков и вместо этого использовать возможности JavaScript, доступные в современных браузерах (в конце концов, вы не делаете не нужен jQuery »):

В этом случае важно использовать true , что означает useCapture в качестве последнего аргумента. Возврат вложенных событий и захват - это два способа распространения событий, происходящих в элементе, который находится внутри другого элемента, когда оба элемента зарегистрировали дескриптор для этого события.

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

Вот скриншот структуры html и веб-страницы.

Использование захвата событий помогает решить эту проблему, а также помогает обнаруживать клики на этой странице.

Почему? Сначала давайте проверим блок-схему ниже (см. Как работает захват и всплытие).

Нам нужно помнить одну важную вещь: пузыри можно остановить.

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

Выделение элемента

При создании расширения Chrome для быстрого отображения форм и веб-сайтов мы стремились:

  1. Предоставлять пользователям максимально возможную визуальную помощь
  2. Помогите пользователям двигаться вперед как можно быстрее.
  3. Помогите пользователям быстро определить любую проблему; и
  4. Обеспечьте визуальное подтверждение того, что все было захвачено правильно (например, когда мы получили селектор, мы выделяем целевой элемент, изменяя его цвет фона на светло-зеленый (#…)).

Чтобы сделать все это, нам сначала нужно найти элемент. Затем нам нужно изменить цвет фона.

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

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

Вот несколько основных логических схем поиска кратчайшего пути:

  1. Проверьте, есть ли у целевого элемента id
  2. Если id существует, убедитесь, что id уникален. (ДА, некоторые веб-сайты используют один и тот же id более двух раз)
  3. Если id не существует или id не уникален, отметьте класс.
  4. Найдите кратчайший путь с помощью селектора классов или используйте тег в качестве идентификатора пути

В конце концов, мы ожидаем что-то вроде ‘input # input-email’, ‘ul # payment-mode-list› li ›a› div ›span’ и т. Д.

Затем мы выделяем элемент:

Шаг 2: Вставка данных

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

Мы называем одно из них действием «значение» (когда значение необходимо ввести или выбрать в форме):

Мы называем другое более простое действие «щелчком», когда все, что нам нужно сделать, это щелкнуть элемент:

Запуск события

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

Например:

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

Что делать, если мы не видим элемент на веб-странице?

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

Посмотрите ниже три скриншота состояния из раскрывающегося списка и сетевую активность при переключении из состояния 1 в состояние 3 (на примере CoffeeCompany.com.au):

Статус 1: раскрывающийся список по умолчанию

Статус 2: Страна выбрана как «США». В раскрывающемся меню "Штат" показаны штаты США.

Статус 3: Страна выбрана как «Австралия». В раскрывающемся списке штатов показаны штаты Австралии.

Захваченный сетевой запрос

Из сетевого журнала видно, что конечная точка состояния вызывалась дважды, когда мы меняли страну.

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

Весь этот процесс обычно происходит в течение 1-2 секунд (в основном в зависимости от скорости сети клиента), но нам нужно заполнить оба раскрывающихся списка не только правильными данными, но и в правильном порядке.

Наилучший способ, который мы нашли для решения этой проблемы, - переопределить объект сетевого запроса (XMLHttpRequest) и заключить его функцию open в наш собственный приемник. Таким образом, мы можем отслеживать, когда XMLHttpRequests запускается / завершаться, и мы можем сообщить нашему движку, когда заполнять или проверять следующий элемент.

Вывод

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

Конечная цель Onefill - сделать покупки в Интернете еще более удобными. Благодаря нашему встроенному движку JavaScript, мы можем оказать лучшую помощь на протяжении всего процесса покупки Onefill.

Автор Dubang Liu.

Некоторые ссылки по теме, которые могут вас заинтересовать:

Http://youmightnotneedjquery.com/

Https://github.com/oneuijs/You-Dont-Need-jQuery

Https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

Https://www.w3.org/TR/DOM-Level-3-Events/#event-flow

Https://davidwalsh.name/javascript-events