Пример Instagram на JS

Небольшой аналог Instagram.

В процессе мы создадим несколько фильтров, которые будут применяться к фотографии в блоке .photo. Переключатели фильтров мы разместим в блоке .toggle-controls, а само переключение будет работать на JavaScript. Cначала подготовим разметку для нашего будущего фотоприложения.

Теперь давайте создадим первый набор фильтров для класса .walden. Набор фильтров применится к большой фото и к переключателю.

Давайте добавим заготовку для ещё одного переключателя. Класс для второго фильтра будет называться toaster.

Затем «отрепетируем» переключение фильтра без использования JavaScript. Для этого пока будем менять HTML-код вручную. При переключении фильтра происходит два события:

Первое. В переключателе класс active перемещается на текущий фильтр:

Второе. У блока с большим фото меняется класс текущего фильтра:

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

Этот фильтр будет делать фото ещё винтажнее, чем walden: сделает его малоконтрастным, с яркими цветами, небольшим поворотом по цветовому кругу и эффектом сепии.

Всё готово для «оживления» интерфейса с помощью JavaScript. HTML-код Кекстаграма приведён в исходное состояние: фильтр ещё не выбран и к фото не применён.

Сначала включим фильтр toaster и применим его к фотографии. Для этого:

1. Найдём элемент списка с классом toaster и сохраним его в переменную control. var control = document.querySelector('li.toaster');

2. Найдём элемент с классом photo и сохраним его в переменную photovar photo = document.querySelector('.photo');

3. Теперь к элементу списка, хранящемуся в переменной control, добавим класс activecontrol.classList.add('active');

4. А к блоку большой фотографии, она уже в переменной photo, добавим класс toaster: photo.classList.add('toaster');

Теперь попробуйте повторить это сами. Обратите внимание, что при добавлении класса с помощью classList.add точка в начале строки не пишется.

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

1. Снова найдём элемент списка с классом toaster, сохраним его в переменную toasterControl и удалим у него класс active, добавленный ранее: var toasterControl = document.querySelector('li.toaster'); toasterControl.classList.remove('active');

2. Найдём элемент списка с классом walden, сохраним его в переменную waldenControl и добавим ему класс active: var waldenControl = document.querySelector('li.walden'); waldenControl.classList.add('active');

3. Найдём элемент с классом photo и сохраним его в переменную photo. var photo = document.querySelector('.photo');

4. Удалим у фото класс toaster и добавим класс walden: photo.classList.remove('toaster'); photo.classList.add('walden');

Разберёмся подробнее в том коде, который мы написали. Вот один из фрагментов:

var toasterControl обозначает, что мы создаём переменную с именем toasterControl.

document – это специальная переменная, в которой хранится корневой элемент HTML-документа, будем называть его просто «документ». В нём хранятся все остальные теги.

querySelector – это метод документа, который по указанному селектору ищет и возвращает первый найденный элемент, подходящий под селектор. В этом методе можно использовать любые CSS-селекторы, уже знакомые вам.

Метод querySelector не всегда может найти элемент и тогда переменная остаётся пустой. Чтобы проверить, что в переменной есть элемент и с ним можно работать, используется условный оператор if.

У элементов, которые мы находим с помощью querySelector, есть свойство classList, в котором хранится список классов элемента.

Список классов можно изменять, удаляя или добавляя в него классы с помощью методов add и remove свойства classList.

Теперь немного отдохнём от JavaScript и создадим ещё один фильтр.

Вернёмся к JavaScript и немного улучшим наш код. Посмотрите эти строчки: var control = document.querySelector('li.toaster'); photo.classList.add('toaster');

Название фильтра toaster в коде повторяется два раза, Карл. Чтобы «переключить» фильтр, придётся поменять код в двух местах. А это лишняя работа!

Избавимся от дублирования. В начале кода создадим переменную с названием фильтра: var filterName = 'toaster'; В метод поиска элементов мы передаём строку li.toaster. Чтобы получить такую же строку из переменной, воспользуемся операцией «склеивания» строк: 'li.' + filterName // результат: 'li.toaster'

В коде для поиска переключателя заменим строку на выражение с переменной:

Внутри photo.classList.add находится такое же значение, как и в переменной, поэтому просто заменяем строку на переменную:

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

Функция создаётся выражением, начинающимся с ключевого слова function. Например, в этом коде мы создаём функцию для суммирования чисел c именем sum:

У функции есть набор параметров, в нашем случае это переменные a и b, и тело, которое выполняется при вызове функции. Тело функции заключается в фигурные скобки. Количество параметров может быть любым, их может и не быть вовсе.

Обернём наш код для переключения фильтров в функцию toggleFilter, у которой будет один параметр — filterName. А затем вызовем функцию с разными названиями фильтра в качестве параметра.

Кстати, переменная filterName нам больше не нужна, так как название фильтра передаётся в функцию в параметре с таким же именем, поэтому в коде создание переменной закомментировано.

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

Если же вызвать созданную функцию несколько раз подряд с разными параметрами: toggleFilter('toaster'); toggleFilter('kelvin'); То активными станут сразу несколько переключателей, а к фотографии применятся несколько фильтров одновременно.

У HTML-элементов есть возможность создавать специальные атрибуты, в которых можно хранить вспомогательную информацию и легко передавать её в JavaScript. Такие атрибуты начинаются с префикса data-.

При этом data-атрибуты валидны и никак не влияют на отображение элементов в браузере.

Давайте добавим переключателям data-атрибуты data-filter, в которых будем хранить название каждого фильтра.

Чтобы с помощью JavaScript считать значение data-атрибутов, нужно использовать свойство dataset. Пример:

В свойстве dataset HTML-элемента хранятся все значения его data-атрибутов. Обратиться к ним можно по названию data-атрибута, удалив из названия приставку data-.

Добавлять содержимое в HTML-элемент через JavaScript можно с помощью свойства innerHTML:

Присвоенная свойству innerHTML строка заменяет всё содержимое HTML-элемента. В этой строке можно использовать любой HTML-код.

Если нужно совершить несколько однотипных действий, то можно использовать цикл for. Вот его синтаксис:

Ранее мы использовали метод querySelector, который возвращает только один элемент: первый элемент, соответствующий селектору.

Другой метод querySelectorAll возвращает все элементы, соответствующие селектору.

С помощью for удобно перебирать найденные элементы:

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

Лучше найти все переключатели внутри списка и перебрать их с помощью цикла. И внутри цикла задавать название каждому переключателю.

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

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

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

На предыдущем шаге мы уже находили все переключатели и сохраняли их в переменную controls: var controls = document.querySelectorAll('.toggle-controls li'); Теперь мы можем использовать эту переменную внутри функции — добавить в начало функции ещё один цикл, который пройдётся по всем переключателям и удалит у них класс.

Ошибку с выделением активного переключателя исправили. Осталась вторая ошибка: фильтр на большой фотографии применяется неправильно. Причина — лишние классы фильтров у большой фотографии. Вот что происходит с HTML, когда функция переключения вызывается несколько раз: <div class="photo walden toaster kelvin"></div>

Чтобы исправить ошибку, надо удалять классы фильтров у блока фотографии при каждом переключении. Но класс photo удалять нельзя. Классы фильтров мы знаем, ведь они хранятся в data-атрибутах переключателей.

Поэтому в том же цикле, где сбрасывается класс active, можно у каждого переключателя брать название фильтра и удалять этот класс у большого фото:

И ещё одна важная деталь. Переменная photo теперь используется в самом начале функции, поэтому мы вынесем строчку поиска переменной из функции в самый верх кода: var controls = document.querySelectorAll('.toggle-controls li'); var photo = document.querySelector('.photo');

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

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

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

В этом фрагменте кода мы сделали следующее:

  1. Нашли элемент списка и у него вызвали метод addEventListener.
  2. Указали отслеживать событие click или «щелчок мыши».
  3. Для щелчков указали функцию-обработчик без названия, внутри которой вызвали функцию переключения фильтров.

Метод addEventListener был вызван у одного элемента, поэтому будут обрабатываться события только этого элемента. Первый параметр задаёт тип события, второй — функцию-обработчик.

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

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

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

Функция clickControl принимает найденный элемент и добавляет ему обработчик щелчков мыши, в котором вызывается функция переключения фильтра. Название фильтра для функции переключения берётся из data-атрибута самого элемента.

Благодаря clickControl нам нужно добавить только одну строчку в цикл, чтобы все переключатели заработали:

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

1. Изменим обработчик внутри clickControl:

2. Изменим параметр у toggleFilter, теперь это не строка, а элемент:

3. В toggleFilter передаётся переключатель и искать его уже не надо, удаляем лишний код

4. Название фильтра для фото теперь берём из data-атрибута переключателя:

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

  1. Менять левую координату ползунка-разделителя, чтобы он двигался вправо или влево.
  2. Менять ширину блока с изображением-оригиналом так, чтобы граница фотографий оставалась под ползунком.

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

Чтобы изменить CSS-свойство элемента в скрипте, нужно обратиться к свойству styleэлемента. Например: var element = document.querySelector('.photo-original'); element.style.width = '10px';

В этом коде элементу задаётся ширина 10px.

С помощью element.style можно и получать, и изменять значения свойств.

Но названия свойств в JavaScript не всегда совпадают с их названиями в CSS. Например, CSS-свойство left совпадает с style.left, но CSS-свойство baсkground-color уже отличается: style.backgroundColor.

Результат:

HTML:

CSS:

JS script:

JS separator:

Просто пример:

HTML:

CSS:
JS:

Обсуждение закрыто.