Работа с JS для проверки UX-гипотез

Для проведения A/B тестов важно уметь самостоятельно изменить верстку сервиса. UX-проектировщики регулярно сталкивались и будут сталкиваться с ситуацией, когда нет возможности привлечь для проверки гипотезы менеджера, графического дизайнера, backend и frontend разработчика, а проверить гипотезу надо. В этом случае, необходимо редактировать готовый веб-сервис самостоятельно. Многие возможности JS позволяют не только изменить поведение контролов на сайте, но и получить достаточно много интересных данных с форм ввода. Сразу хочу отметить, что от UX/IA дизайнера никто не должен требовать Production Ready кода, ваш код должен решать лишь ваши задачи.

Давайте рассмотрим, какие возможности браузера и JS нам могут быть полезны в первую очередь. Браузер состоит из DOM и BOM. DOM это документ, со всеми body, div, span и прочими элементами. Все свойства DOM описаны на www.w3.org. BOM—объекты для работы с чем угодно независимо от контента страницы. Для управления DOM и BOM используется JS.

С DOM все понятно, давайте посмотрим на пример работы с BOM. Если разобрать на составляющие адрес в браузерной строке https://your-scorpion.ru/portfolio#about, то

  • функция location.href вернет весь URL
  • location.hostname вернет лишь your-scorpion.ru
  • location.pathname вернет /portfolio/
  • location.hash вернет хэш #about.

 

Это был понятный, но не самый практичный пример возможностей BOM, более практичные примеры будут во второй части статьи. При проведении тестирования важно реагировать на действия пользователя, для этого используются события. Это сигналы от браузера о том, что пользователь сделал какое то действие. Назначить обработчики событий можно следующими способами:

  1. Атрибут HTML: onclick="...".
  2. Свойство: elem.onclick = function.
  3. Метод elem.addEventListener( событие, handler[, phase]).

 

Обработчики событий работают со следующими событиями:

  • click – клик по элементу левой кнопкой мыши
  • contextmenu – клик по элементу правой кнопкой мыши
  • mouseover – на элемент наведена мышь
  • mousedown и mouseup – нажали и отжали кнопку мыши
  • mousemove – любое движение мыши
  • submit – отправил форму, работает в тэге <form>
  • focus – посетитель фокусируется на элементе, например нажимает на <input>
  • keydown – когда посетитель нажимает клавишу
  • keyup – когда посетитель отпускает клавишу
  • DOMContentLoaded – когда HTML загружен и обработан, DOM документа полностью построен и доступен
  • transitionend – когда CSS-анимация завершена

Это далеко не полный список, но это основные события, используемые UX-проектировщиками и дизайнерами при проработке разных состояний контролов.

 

Примеры

<input value="Кнопка" onclick="alert('Сообщение в попапе')" type="button">

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

<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">

  <script>
    function countRabbits() {
      for(var i=1; i<=3; i++) {
        alert("Кролик номер " + i);
      }
    }
  </script>
</head>
<body>
  <input type="button" onclick="countRabbits()" value="Считать кроликов!"/>
</body>
</html>

Здесь используется вызов функции countRabbits(), сама функция написана выше. Функция это то, что умеет создавать значение. Обработчик может быть назначен и на элемент DOM. Выглядит это как on<событие>. Вот пример:

<input id="elem" type="button" value="Нажми меня" />
<script>
  elem.onclick = function() {
    alert( 'Спасибо' );
  };
</script>

Основной минус такого подхода: DOM-свойство onclick одно, и назначить более одного обработчика не получится. Мне, как Flash-разработчику в прошлом, куда ближе методы addEventListener и removeEventListener, которые являются лучшим способом назначить или удалить обработчик, и при этом позволяют использовать неограниченное количество любых обработчиков. Назначение обработчика осуществляется вызовом addEventListener, который имеет три аргумента:

element.addEventListener(event, handler[, phase]);

event—имя события. handler—ссылка на функцию, которую надо поставить обработчиком. phase не обязателен к использованию, отвечает за «место», на которой обработчик должен сработать. Не только пользовательские события могут служить триггером для отработки функции. Рассмотрим пример.

document.addEventListener(
 'DOMContentLoaded',
 console.log("Я отработаль"),
 {once: true}
);
//или проще
document.addEventListener("DOMContentLoaded", ready);

Это очень простой пример, в котором текст «Я отработаль» будет выведен в консоль в тот момент, когда браузер полностью загрузил HTML и построил DOM-дерево. Важно понимать, что событие «Окно загружено» сработает позже всех, т.к. происходит когда окончательно загрузится весь контент и скрипты на странице.

Во втором случае мы вызываем функцию ready. Итак, у вас есть два способа:

document.getElementById('id0').onclick = function() {
    alert('Может быть только один обработчик');
}

document.getElementById('id1').addEventListener('click', function(event) {
    alert('Сколько угодно обработчиков');
})

 

Практические примеры:

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

var button = document.querySelector('button');  //при этом у кнопки есть соответствующий тэг button
button.addEventListener('click', function() {console.log('Button clicked.');

Все работает при условии, что текстовому полю назначен id=’cecer’.  Осталось вместо button clicked слать в консоль содержание поля.

button.addEventListener('click', function() {console.log(document.getElementById('cecer').value);});


Допустим, в форме заявки есть набор блоков, работающих по принципу чек-боксов. Нас интересует узнать, какие опции люди включали и в какой последовательности. Необходимо написать код, и добавить к каждому из блоков уникальный idшник. Результат и код вы можете увидеть ниже.

$('.ui-input-image__input').mouseover(function() {console.log(this.id);});

Безусловно, это очень простые примеры. Мне доводилось писать более 1000 строк кода для получения достаточного количества данных при проверке гипотезы. Написав код, вы добавляете его в Google Tag Manager и проводите A/B тестирование, параллельно собирая данные.

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

  • URL-адрес страницы
  • Триггер—что инициирует получение данных
  • Category—к какому типу относится используемый компонент, Inputs, Buttons, etd
  • PageType—на какой странице или шаге мы находимся
  • Action—описание, что именно делает этот элемент (from/to, дата рождения, etd)
  • Label—значение полей или контролов

Например, Category: order_esignature, Action: esign_CTA, Label: buy_esign. Смысл в том, чтобы потом было удобно и быстро искать нужные события (и понимать к чему они). Разумеется, в рамках такого ТЗ обычно передается и описание всех привязок к Google Analytics.