Slyweb
На разработку сайта! Скидки 50%!

Slybox на jQuery

"Мы все учились по-немного, чему-нибудь и как-нибудь". А. С. Пушкин.
Официальная страница slybox - http://slyweb.ru/slybox/
Если Вы читали мою статью о "Lihgtbox без фреймовика", размещенную в разделе "Javascript", то для Вас будет интересным изучить статью о том же, но объясняющую создание lightbox на jQuery.
Lihgtbox без фреймовика является базовой статьей для создания многих галерей, которые принято называть в интернете "Lightbox". Но она описывает лишь основы, не создавая эффектного lightbox`а.
В этой статье я опишу создание, во всех подробностях, lightbox`а с эффектами от jQuery. После прочтения статьи, надеюсь, Вы сможете создавать собственные модели lightbox`ов, с необходимыми для вас параметрами и эффектами от jQuery.
Итак, начнем. Во-первых, как я говорил в статье "Lihgtbox без фреймовика" уровень знания прежде всего jQuery, а по том уже javascript, должен быть опытным, ближе к высокому. Если вы не понимаете разницу между событиями mouseenter и mouseover или не знаете как правильно определить загрузку изображения с помощью события load, то Вы должны для начала изучить jQuery, хотя-бы прочтением всех методов jQuery на данном сайте.

Теория. Эргономика и дизайн.

Любой lightbox строится c целью улучшить взаимодействие пользователя с изображениями и получении им информации об изображении. Исходя из этого должны быть выбраны эргономика и дизайн Lihgtbox. Например, размещение элементов управления на основном контейнере Lihgtbox`а должно обеспечивать видимость самого изображения, загрузка изображения должна сопровождаться элементом уведомляющим о загрузке(например, изображение крутящегося loader`а), элементы управления должны корректно появляться и скрываться. Обязательно выводить информацию об изображении (alt) в основном контейнере при наведению курсора на изображение, а не автоматически.

Теория. Базовые функции jQuery.

Как и везде базовая функция jQuery - "$(document).ready(function(){...});". Если Вы еще не знаете, что она позволяет работать со структурой DOM после её полной загрузки, то есть код расположенный в "..." будет выполняться только после того, как все элементы document будут загружены браузером на 99%, то знайте же об этом. Эта функция оборачивает остальные методы jQuery, если Вы разместите за её пределами какие-либо методы или функции, то они будут выполнены либо до загрузки DOM либо в процессе её загрузки, то есть возможно когда метод будет обращаться к элементу еще не появившемуся на странице и, следовательно, это вызовет ошибку - "К чему Вы обращаетесь?".
Может быть не принято объяснять код непоследовательно - не сверху вниз, но я буду объяснять выполнение кода jQuery именно непоследовательно, то есть по степени очередности выполнения функций при запуске Slybox`а.

Практика. Наш Slybox на jQuery.

Очередность функций такова:
Первый этап - пользователь наводит курсор на изображение, в slybox при этом, изображение меняет значение свойства opacity с 0.3 на 1:
Как Вы правильно догадались, это необходимо для того, что бы показать пользователю, что минизображения обладают интерактивностью, то есть с ними можно что-то сделать, например нажать, при этом не забывайте в листах стилей установить свойство cursor как pointer, чтобы еще убедительнее воздействовать на пользователя и побудить его нажать на минизображение.
Итак, пользователю понравился наш эффект плавного увеличения четкости изображения и он решил нажать на минизображение, какой был бы толк от slybox`а, если бы мы не написали следующую фукцнию:
Объясняю её назначение - при нажатии по элементу с класом "mini-lightbox", то есть по любому существующему минизображению, во-первых, запускается функция bigimg(this), во-вторых у элемента с классом "imgindex" очищается атрибут active, а затем вновь заполняется значением active. Элемент с классом "imgindex" - это любой элемент - контейнер, содержащий минизображения. В этой функции мы находим его перемещаясь от текущего объекта, обозначенного словом this (это минизображение по которому щёлкнули) к родительскому элементу с помощью метода parent(), данный метод позволяет получить доступ к родительскому элементу от дочернего элемента. Вы спросите, а зачем очищать и заполнять атрибут active? Я отвечу - это необходимо для того, чтобы определить текущий элемент с классом "imgindex", у нас на странице он ведь может быть не один, пользователь на вставляет изображений по всей странице и начнет по ним нажимать. И как я по вашему должен определить в каком блоке контейнере была нажато мниизображение? Только так, пометить его дополнительным атрибутом "active", но Вы можете спросить, а зачем этот же атрибут сперва очищать? А я отвечу - блок "imgindex" с атрибутом active должен быть один! А почему, если Вам интересно - удалите эту строку и посмотрите в браузер! Ладно, пойдём далее. А далее фукцния bigimg(this). Она является основной функцей slybox`а. В неё мы передаём объект минизображение. В ней мы его обрабатываем и на основе этого создаём увеличенное изображение.

Основная функция slybox`а - bigimg().

Посмотрите на следующие первые строки функции bigimg:
Для начала мы удаляем элементы с id close,next,prev,comment,conteiner, мы делаем это для того чтобы предыдущие элементы с этими же id не сохранились на странице. Элементы с указанными id - это элементы благодаря которым будет создаваться контейнер содержащий увеличенное изображение, элементы управления (кнопки slybox`а). При каждом нажатии минизображения будут создаваться элементы с данными id и, если их предварительно не удалить, то на странице появятся не нужные нам дубликаты элементов, что в свою очередь нарушит работу slybox`а.
После того, как мы их удалили, нам необходимо их заново создать, что и делает вторая строка, с помощью метода append мы присоединяем html код к телу страницы. Теперь мы можем работать с элементами. После этого, нам нужно убрать элемент с id conteiner а границы видимости окна.
Первая строка скрывает основной элемент, в котором содержатся дополнительные элементы и будущее увеличенное изображение, смещение элемента за границы вьюпорта принято называть техникой оффсетлефт(offsetleft). Она применяется для того, чтобы за границами вьюпорта на некоторое время отобразить "кривой" контейнер с набором "кривых" элементов управления и увеличенным изображением для того чтобы получить действительные размеры увеличенного изображения. Зачем, спросите Вы меня, нужно применять эту технику? Может быть вы предложите получить размеры без использования данной техники? Я отвечу - это невозможно, поскольку контейнер "#conteiner" скрыт с использования метода hide(), метод hide() скрывает элемент, устанавливая css свойство display как none, а как Вы знаете у элементов, в отношении элементов у которых установлено данное свойство, невозможно получить свойства высоты и ширины, так как его нет на странице. Далее Вы увидите как только будут вычислены действительные значения высоты и ширины увеличенного изображения и на основе этого вычислено положение при котором блок будет плавно появляться на странице, блок будет перемещен соответственно на его обоснованное центральное место. Вторая строка скрывает элементы управления - кнопки вперед, назад, закрыть и блок с комментарием. Это необходимо для того чтобы их разместить в блоке "#conteiner" а при его полной загрузке плавно отобразить.
После этого идут такие строки:
В первых двух строках мы получаем высоту и ширину вьюпорта (видимая часть окна браузера, не вся страница), далее мы получаем смещение относительно верхней границы окна браузера до вьюпорта (offset), после этих строк мы сохраняем в переменных centerimg, centerimgt значения, с помощью которых далее центрируем блок указывающий на загрузку изображения (#load). Для того, чтобы отцентрировать блок, нам необходимы его значения высоты и ширины и те же значения вьюпорта, после чего мы делим те и другие на 2, чтобы получить центр вьюпорта по ширине и по высоте и отнимаем от этого центра половину ширины и высоты блока (#load), таким путём мы получаем значение необходимое для смещения блока (#load) от верхнего и от левого краёв. После чего, соответственно, в последней строке и смещаем блок, устанавливая с помощью метода jQuery css() свойства top и left. Только заметьте мы еще добавляем к высоте смещение методом scrollTop(), иначе наш блок, может оказаться на верху страницы, если допустить, что изображения расположены на странице, где-нибудь за пределами изначального вьюпорта, до которых необходимо ещё скроллить.
После чего Вы должны увидеть строки:
Не пугайтесь, здесь всё просто. В первой строке мы пытаемся установить какое минизображение сейчас является активным, то есть то, на основании которого мы загружаем увеличенное изображение. Если ни у одного из миниизображений нет атрибута active то переменная index будет содержать -1, иначе мы удаляем значение атрибута active и далее устанавливаем этот атрибут в минизображение по которому только что нажали - теперь у нас есть активное минизображение. Активное минизображение нам необходимо для того чтобы определять в дальнейшем с помощью функций можно ли перемещаться к следующему или предыдущему минизображению. С помощью нижеуказанных строк мы проверяем установлен ли эффект затемнения, на фоне которого должно появиться увеличенное изображение. Если установлено, то удаляем и его и увеличенное предыдущее изображение, так как контейнер #conteiner должен содержать новое увеличенное изображение.
Следующая строка кода, не сороки комментариев, извлекает из мниизображения, по которому нажали, значение атрибута src и далее с помощью метода replace заменяет в нём символы "_s" на "". Для чего это нужно? Это необходимо для того, чтобы получить путь к увеличенному изображению, например, у Вас есть минизображение "20100614035010_s.jpg" размером 100 на 100 в папке images и там же должно быть изображение "20100614035010.jpg", если этого изображения там нет или оно называется по-другому то, по-просту говоря, увеличенное изображение не загрузится. Для чего мы так сделали с атрибутами src? По - моему это очень удобно для работы с минизображением и его максимальной копией. Пользователю slybox нужно будет лишь создать два изображения с почти одинаковыми src - уменьшенное и увеличенное, и к первому добавить символы '_s', после этого он сможет при нажатии получить из уменьшенного изображения увеличенную копию. У такого подхода есть ещё один плюс - пользователь не должен разбираться в html и создавать какие-либо элементы в которых будет хранится информация об изображениях. К примеру посмотрите в других lightbox`ах, там чтобы указать на минизображение нужно создавать элемент "a", а внутри него создавать элемент "img". В slybox` е все просто. // создание атрибута src для максимального изображения
По сути говоря следующий код немного ошибочен, поверка существования элемента с id conteiner вряд-ли нужна, я думаю и без неё все буде работать, но решил оставить на всякий случай.
Если изображения нет на странице, то создаём новый объект изображения (var newim = new Image();) и запускаем функцию attevent(newim,e). Будьте внимательны если поместите данную функцию после того как новому объекту изображения будет присвоено значение src (newim.src = esrc;), то обработчик события load не будет запущен в некоторых браузерах или будет запускаться не всегда. В нашем случае функция attevent(newim,e), по-сути, и есть обработчик события load, она содержит функцию обработчик под названием hendler, которая запускается когда срабатывает событие load для нашего изображения, то есть когда увеличенное изображение загрузится полностью на страницу, функция запускается благодаря функции jQuery load(), привязанной к новому изображению ($(newim).load(hendler);).

Основная функция slybox`а - attevent().

Итак, из функции bigimg мы переходим к функции attevent(newim,e), в которой нам важна функция hendler, рассмотрим её подробно.
Чтобы значила первая строка в рассматриваемой функции? Мы присоединяем к элементу с id conteiner(наш контейнер содержащий увеличенное изображение и элементы управления) с помощью метода append увеличенное изображение с id bigimg, устанавливая атрибут src из нового объекта изображения (newim.src).
Указанные строки необходимы здесь для не особо развитых браузеров, с помощью функции bind() мы связали событие mouseleave с его обработчиком mouseouthandler и mouseoverhandler. Указанные обработчики будут описаны позднее,так как они являются вспомогательными функциями нашего скрипта, сейчас лишь объясню, что их необходимо прописывать именно в этом месте функции из-за того, что аналогичные строки кода существуют вне рамок функции handler однако они при нажатии кнопок управления отключаются соответствующими методами unbind(), для того чтобы не инициировать события mouseleave и mouseenter после того как будут нажаты кнопки управления. Если Вы уберете функцию unbind(), то получится так что при нажатии кнопки next блок контейнер начнет плавно исчезать, но Вы наведете курсор на него вновь и при этом сработают события mouseleave и mouseenter получится что блок скрывается а кнопка вновь появляется на нём, что не правильно, по моему мнению. К тому же я начал этот абзац про упоминание о неразвитом браузере, так вот в нём, если убрать данные строки события могут вообще не произойти.
Далее следуют две функции getDocumentHeight и getDocumentWidth, с их помощью мы кроссбрузерно получаем высоту и ширину всей страницы(! не только высоту и ширину вьюпорта) и сохраняем пол ученые значения в переменные bh и bv:
Указанные значения необходимы для того чтобы создать эффект затемнения информации на странице при загрузке изображения, что и делает следующая строка кода:
Далее мы скрываем наш загрузчик, нам ведь он не нужен сверху увеличенного изображения:
После этого мы получаем значения высоты, ширины как вьюпорта, так и всей страницы, и смещение относительно верхней границы окна браузера (var offset)
Указанные значения необходимы нам для центрирования основного блока, который будет содержать увеличенное изображение.
Следующие строки позволяют определить выступает ли наше изображение за пределы границ активного окна браузера, если их удалить может получиться так, что часть изображения будет выведена за верхний край окна браузера, это не позволяет сделать первая стока:
В ней мы проверяем больше ли значение высоты контейнера (imt) значения высоты вьпорта (document.documentElement.clientHeight), если да, то мы, просто-напросто, смещаем контейнер на 10px от верхней границы окна браузера, таким образом, пользователь сможет увидеть во вьюпорте, в окне, которое перед ним находится, изображение хотя и больше высоты самого вьюпорта, но верхняя граница которого будет в пределах видимости для пользователя, то есть ему не нужно будет прокручиваться страницу вверх. Надеюсь Вы поняли о чём я говорю.
Строка var centerimg = Math.abs((imb/2) - (iml/2)); делает то же самое с шириной экрана, замечу что данная строка не доработана до конца, так как если изображение будет больше ширины вьюпорта, оно будет не ровно смотреться в окне. Поэтому допишите соответствующий код самостоятельно.

Самое интересное!

Вот мы и добрались до сердцевины slybox`а, благодаря которой происходит размещение изображения по середине экрана с эффектными плавного отображения изображения:
Методы jQuery hide() и fadeOut() скрывают элемент id conteiner, после этого с помощью метода css({}) элемент выравнивается по центру окна браузера, помните я говорил о технике offsetleft - мы сперва сместили блок на -5555px, а после этого вернули его на центр окна браузера.
После того как мы его вернули на центр окна браузера, с помощью метода fadeIn()(fadeIn('slow')) медленно начинаем его отображать, то есть изображение плавно появляется, затем выполняем функцию обратного вызова метода fadeIn(), в которой с помощью метотда attr() ($("#conteiner").attr('terget','1');) мы позволяем пользователю в дальнейшем скрывать изображение не только нажатием по кнопе close, но и по остальной части окна не заполненной изображением. Если значение terget равно 1 то это означает, что на странице существует контейнер с увеличенным изображением, если это значение равно 0, то ни изображения ни контейнера нет. Исходя из этого и будет работать код расположенный вверху скрипта:
Как Вы видете при нажатии по элементу body происходит проверка - содержания элементом с id conteiner атрибута target равного 1, если true, то выполняется последующий код, в котором мы с помощью объекта event проверяем id текущего элемента, на котором было произведено нажатие кнопки мыши. При нажатии на элементах с id перечисленными в данной функции не будет запущена функция delshadow(), та функция которая ответственна за удаление контейнера с id "conteiner" и самого увеличенного изображения, поскольку для некоторых из этих элементов есть собственные собтия click либо события клик отсутствуют, но они не должны срабатывать на этих элементах. Принцип такой - при нажатии всего чего - либо другого, за исключением элементов с указанными id, функция delshadow() должна быть запущена, иначе нет.
Сейчас, после небольшого отступления, я напомню, мы говорили о сердцевине нашего slybox`а обработчике handler() и остановились на строках:
Теперь вы должны понимать назначение этой строки. Если нет удалите её и всё поймете! А мы идём далее!
Указанный код размещает элемент с id close, то есть как Вы и догадались кнопку "закрыть" в правом верхнем углу контейнера с увеличенным изображением (свойство left равно ширине контейнера минус ширину самой кнопки - 'left':iml-76).
За ним Вы увидите две закрывающиеся фигурные скобки,- наш обработчик подошел к окончанию.
Мы рассмотрели две из основные функции slybox`а - bigimg и handler, однако другой не менее важной функцией является функция delshadow():
Данная функция ответственна за удаление основного контейнера и увеличенного изображения, а так же за эффекты существующие при этом. Начинается она с установления атрибута target равным 0, зачем нужен данный атрибут я объяснял выше в статье. После этого мы проверяем существование элемента с id shadow. Если элемент существует, то продолжаем выполнение функции далее:
Данные строки нужны для того чтобы предотвратить неправильную работу плавного сокрытия кнопок вперед(назад). Представьте себе вы нажали кнопку close и запустили функцию delshodow() кнопки начинают плавно скрываться, однако вдруг пользователь начинает водить по вьюпорту курсором, тогда начинают срабатывать события mouseenter и mouseleave, а для них предусмотрены в скипте соответствующие обработчики, тогда получается, что кнопки как-бы начали скрываться, но тут же благодаря обработчикам начинают появляться, правда не логично?
Затем начинаем удалять одновременно наши элементы управления (#next,#prev,#close,#comment) плавно, с эффектом от jQuery, с использованием метода fadeOut() - метод изменяющий свойство opacity с использованием анимации. После этого мы плавно скрываем контейнер, а затем в функции обратного вызова, запускаемой только после того, как закончится анимация удаляем само увеличенное изображение:
Затем удаляем эффект затемнения:

Вспомагательные функция slybox`а.

Я думаю три указанных функции составляют основу большинства lightbox`ов. Но они не мыслимы без вспомогательных функций у нс их в скрипте несколько. К ним относится весь оставшийся код который я не рассмотрел, то есть строки с 99 по 165, перечислим пользовательские функции:
  • mouseoverhandler()
  • mouseouthandler()
  • nextimg()
  • previmg()
Первая функция, как не сложно догадаться является обработчиком события, но только не mouseover ,а mouseenter, указанное событие более всего подходит в нашем случае, так как элементы находятся внутри контейнера и если бы Вы использовали событие mouseover, то при наведении курсора на кнопку, а затем обратно на изображение срабатывала функция обработчик, то есть кнопки бы повторно не эстетично мигали на картинке. Теперь рассмотрим её подробно. Строки:
Первая строка не сложная, оставлю её комментарий. Во второй строке мы находим индекс текущего изображения, вспоминает строки в функции bigimg, где бы устанавливали минизображение как активное с помощью атрибута active. Так как jQuery функция index() предоставляет индекс начиная с нуля, то мы его увеличили на 1 для более удобной работы в дальнейшем при сравнивании индекс с количеством минизображений.
Далее идёт проверка:
Если текущий индекс равен количеству минизображений в активном блоке (блок с классом imgindex и атрибутом activeравным active) и и количество минизображений не равно 1, то мы находимся на последнем из миниизображений и, следовательно, нам необходимо показать только кнопку назад(back). Что мы и делаем с помощью следующей строки:
Далее снова проверяем:
Если текущий индекс минизображения равен 1 и и количество минизображений больше 1,то мы находимся на первом минизображении, соответственно допустима кнопка вперед (next), её мы и отображаем:
Далее опять проверяем:
А вдруг у нас больше одного изображения, но мы находимся на изображении, являющимся не первым и не последнем, тогда необходимы кнопки взад и вперёд:
Последняя строка данной функции завершатся плавным показом комментария:
Функция mouseouthandler - обработчик выполняемый при отведении курсора от изображения, при нём должны быть убраны все элементы управлени
Оставшиеся две пользовательские фукнции nextimg() и previmg() ответственны за переход к предыдущему или следующему изображению, расположенному в блоке с id index. Внутри каждой мы сперва свертываем элементы с id shadow, conteiner. После чего, запускаем функцию bigimg().
Напоследок рассмотрим оставшиеся не рассмотренными в нашем скрипте строки кода:
В первых трех строчках кода мы с помощью jQuery функции live() привязываем обработчики событий для события click. Указанные обработчики есть не что иное как ранее рассмотренные функции nextimg(), previmg(), delshadow().
Наибольший интерес для Вас вызовет строка:
Что она делает? Для улучшения качества нашего slybox`а мы предусмотрели эффект, с помощью которого кнопки вперед и назад отображаются и скрываются плавно при наведении на основной контейнер и отведении от него курсора мыши.
Однако представьте Intenet Explorer отказываться корректно выводить данные кнопки в окне, смещая их до появления контейнера, то есть ли Вы щёлкнули по кнопке вперед или назад и в этот же момент не отключили с помощью функции unbind обработчик mouseouthandler для события mouseleave, то оно будет продолжаться срабатывать даже тогда когда контейнер "уйдет налево" на -5555px и будет возвращаться обратно на центр экрана только с новым изображением. И что у нас в этом случае получится, получится так что событие сработает ещё до получения действительного значения ширины и высоты основного контейнера с id conteiner. Это так на мой взгляд, хотя я в этом пока не уверен на 100%, для меня это гипотетически верно и лишь в отношении браузера Internet Explorer, в других браузерах не зачем данная строчка, всё работало и без неё. Поэтому для устранения данного бага напишем последние строки:
В них мы при нажатии кнопок с id #prev,#next отключаем обработчики событий для событий mouseleave и mouseenter. В результате чего изображение начинает плавно скрываться и при наведении на него во время выполнения данного эффекта, не происходит повторного «мигания» кнопок вперед, назад.
На этом статья о создании собственного lightbox на jQuery завершена. Могу лишь добавить, если Вам не всё ясно не расстраивайтесь, после изучения подробного описания jQuery функций на данном сайте Вы разберетесь в ней.
Возможно Вам понадобится весь код slybox, вот он - slybox.js Официальная страница slybox - slybox

Александр Ермаков