• Главная»
  • Уроки»
  • jQuery»
  • Три варианта создания компонента для переключения контента: jQuery, JS, CSS

Три варианта создания компонента для переключения контента: jQuery, JS, CSS

Не так давно, одна моя подруга создала компонент пользовательского интерфейса для изменения содержимого страниц, на основе элемента <select>. Код работал, но, т.к. JavaScript был для неё в новинку, она создала jQuery компонент и попросила меня помочь оптимизировать его.

Вот приблизительно тот код, который она написала:

<div class="select-area">
  <select name="choose" id="choose" class="input-select">
    <option value="nul" selected>Make a Selection</option>
    <option value="opt1">Option 1</option>
    <option value="opt2">Option 2</option>
    <option value="opt3">Option 3</option>
  </select>
</div>

<section class="jqueryOptions opt1">
  <div class="content">
    <h2>Option 1 Content</h2>
    <p>
      ...
    </p>
  </div>
</section>

<section class="jqueryOptions opt2">
  <div class="content">
    <h2>Option 2 Content</h2>
    <p>
      ...
    </p>
  </div>
</section>

<section class="jqueryOptions opt3">
  <div class="content">
    <h2>Option 3 Content</h2>
    <p>
      ...
    </p>
  </div>
</section>

jQuery-код для переключения контента после небольшой оптимизации:

$(function() {
  $('.jqueryOptions').hide();

  $('#choose').change(function() {
    $('.jqueryOptions').slideUp();
    $('.jqueryOptions').removeClass('current-opt');
    $("." + $(this).val()).slideDown();
    $("." + $(this).val()).addClass('current-opt');
  });
});

Так что здесь происходит?

Вышеупомянутая функция jQuery ищет все блоки содержания, у которых есть класс "jqueryOptions”, и скрывает их из виду.

Тогда, когда пользователь выбирает какой-то пункт у элемента select (с ID 'choose'), функция закрывает все потенциально открытые блоки контента, используя jQuery метод .slideUp(), а затем открывает выбранный нами блок с помощью slideDown(). Реализуется это за счёт выбора опции элемента select (через ключевое слово this) и нахождению элемента с именем класса, который соответствует значению “this”.

Итак:

<option value="opt1">Option 1</option>

Соответствует:

<section class="options opt1">
  ...
</section>

Демо на CodePen.

Не слишком сложно, не правда ли?

Так почему бы не оставить все как есть?

Проблема состоит в том, что для столь маленького кусочка функциональности нам пришлось загрузить jQuery библиотеку (сжатую до 98 КБ). Мы могли сделать лучше.

Не меняя разметку, давайте посмотрим, как мы можем создать такой ??же эффект сперва используя чистый JavaScript, а затем, используя только CSS.

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

  • Содержание должно быть скрытым по умолчанию;
  • После смены пункта элемента select, мы должны показать выбранный контент;
  • После смены пункта элемента select, скрыть весь остальной контент.

Есть ещё несколько деталей, но их мы раскроем по мере написания кода. Итак, первый пункт мы можем реализовать при помощью CSS, так что его можно вычеркнуть. Осталось два.

Реализация с помощью JavaScript

Для начала, давайте создадим несколько переменных:

var selectInput = document.getElementById('choose'),
    panels = document.querySelectorAll('.options'),
    currentSelect,
    i;

Теперь у нас есть прямой доступ к таким элементам страницы, как элементу select (selectInput), блоки с различным содержанием (panels), плэйсхолдер для текущего варианта и итератор.

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

Для начала реализуем скрытие контента страницы при выборе нового значения элемента select. Для этого мы создадим функцию:

function clearShow() {
  for ( i = 0; i < panels.length; i++ ) {
    panels[i].classList.remove('show');
  }
}

Функция clearShow() действует следующим образом: во-первых, она берет переменную panels (которая представляет собой список всех блоков на странице с классом “options”), перебирает каждый (три в данном случае) и удаляет класс “show”.

Класс "show" – отвечает за отображение контент на нашей странице.

Теперь, когда у нас есть способ, удалить класс “show” из каждого блока с контентом, нам нужен функционал, который сделает обратное действие:

 function addShow(showThis) {
  var el = document.getElementsByClassName(showThis);
  for ( i = 0; i < el.length; i++ ) {
     el[i].classList.add('show');
   }
}

Функция addShow() принимает аргумент под названием showThis и добавляет к нему класс “show”, название которого совпадает с выбранным значением поля select. Теперь нам нужно передать значение showThis в addShow().

function vUpdate() {
  currentSelect = selectInput.value;

  clearShow();
  addShow(currentSelect);
}

selectInput.addEventListener('change', vUpdate);

Функция vUpdate() выполняется всякий раз, когда обновляется пункт элемента select (отслеживающийся с помощью события change):

  • Выбираем текущее значение selectInput и сохраняет его в переменной currentSelect;
  • Выполняем функцию clearShow, чтобы удалить все классы show из панелей;
  • Выполняем функцию addShow(), передав currentSelect для отображения нового контента.
  • Присваивает класс show панели с новым контентом.

Демо на CodePen.

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

Мы можем исправить это, добавив, следующее:

if (selectInput.value !== 'nul') {
  currentSelect = selectInput.value;
  addShow(currentSelect);
}

Тут мы сравниваем значение selectInput с nul. Если они не равны, то передаём значение текущего элемента списка в функцию addShow(), что запустит перезагрузку страницы.

Если вам нужна поддержка Internet Explorer 9 или ниже, мы не сможем использовать classList(). Чтобы обойти эту проблему, воспользуемся функциями для добавления и удаления классов из элемента:

function addClass(elm, newClass) {
    elm.className += ' ' + newClass;
}

function removeClass(elm, deleteClass) {
  elm.className = elm.className.replace(new RegExp("\\b" + deleteClass + "\\b", 'g'), '').trim();
  /* the RegExp here makes sure that only
     the class we want to delete, and not
     any other potentially matching strings
     get deleted.
  */
}

Реализация при помощи CSS

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

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

Именно поэтому нам нужно будет воссоздать элемент select, используя хак "radio button".

Вот наша новая разметка:

<input type='checkbox' class="invis" id="open_close" />
<input type='radio' name='opts' class="invis" id="opt1" />
<input type='radio' name='opts' class="invis" id="opt2" />
<input type='radio' name='opts' class="invis" id="opt3" />

<header class="header-base">
  <div class="content">
    <p>
      Choose an Option
    </p>

    <div class="select-area">
      <label for="open_close" class="input-select">
        ...
      </label>

      <ul class="select-options">
        <li>
          <label for="opt1">Option 1</label>
        </li>
        <li>
          <label for="opt2">Option 2</label>
        </li>
        <li>
          <label for="opt3">Option 3</label>
        </li>
      </ul>
    </div>

  </div>
</header>

Тут мы создали свой собственный элемент select. Используем неупорядоченный список и метки в качестве элементов нашего списка.

Метки opt1, opt2, и opt3 меняют состояние ckecked радио кнопки с соответствующим ID. В CSS для доступа к нужному элементу воспользуемся селектором ~.

#opt1:checked ~ main .opt1,
#opt2:checked ~ main .opt2,
#opt3:checked ~ main .opt3 {
  display: block;
  height: 100%;
  overflow: visible;
  visibility: visible;
}

Но тут возникает проблема, которую нам нужно решить: если кликнуть по тому же элементу списка, то контент сначала исчезнет, потом снова появится.

Для исправления этого изъяна, я добавил <input type="checkbox" class="invis" id="open_close" />. К тому же и реализовал возможность закрытия списка, добавив кнопку X:

#open_close:checked ~ .header-base .select-area .select-options {
  opacity: 1;
  visibility: visible;
}

#open_close:checked ~ .header-base .select-area:after {
  border: none;
  content: 'X';
  top: -24px;
}

Далее нужно реализовать, чтобы при смене элемента списк, текст верхнего элемента так же менялся. Для этого воспользуемся псевдо-классом :before:

.input-select:before {
  content: 'Make a Selection';
}

#opt1:checked ~ .header-base .input-select:before {
  content: 'Option 1';
}

#opt2:checked ~ .header-base .input-select:before {
  content: 'Option 2';
}

#opt3:checked ~ .header-base .input-select:before {
  content: 'Option 3';
}

Вы можете видеть вышеупомянутое, тем более в действии, просматривая исходный код демонстрационного примера CodePen только для CSS:

Демо на CodePen.

В заключение, краткое резюме о плюсах и минусах ...

Мы только что рассмотрели три различных способа реализации одной и той же задачи, используя JQuery, затем чистый JavaScript, чистый CSS. В каждом подходе есть свои плюсы и минусы.

Решение на основе jQuery является самым простым, и состоит из пары строк кода.

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

Решение на основе JavaScript очень похоже на предыдущее. Выигрываем в скорости загрузки страницы.

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

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

Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: http://www.sitepoint.com/content-switching-component-built-three-ways/
Перевел: Станислав Протасевич
Урок создан: 15 Октября 2014
Просмотров: 22487
Правила перепечатки


5 последних уроков рубрики "jQuery"

^ Наверх ^