Jquery viewport - проблема реализации адаптивного меню
Здравствуйте, готовлю сайт-одностраничник - 5 блоков на 100% ширины и высоты и фиксированное меню из якорных ссылок, ведущих к этим блокам. Нужно, чтобы при прокрутке вручную или с помощью меню, при нахождении в каком-либо из 5-и блоков соответствующий пункт меню получал класс "selected". В ходе поисков нашёл плагин jquery viewport и прилагающийся скрипт, но что-то не смог адаптировать под свой сайт:
// add & remove active link $(document).ready(function() { $(window).scroll(function () { var inview = '#' + $("section > article:in-viewport:first").parent().attr('id'), $link = $('nav a').filter('[hash=' + inview + ']') if ($link.length && !$link.is('.selected')) { $('nav a').removeClass('selected'); $link.addClass('selected'); } }) }); |
ловить .scroll и проверять совпадение с позицией блоков: http://learn.javascript.ru/play/R6einb
|
По сути нужно, чтобы javascript сравнивал id блока, в кот-ом мы сейчас находимся, с адресом якорной ссылки (в адресе - id блока). И при их совпадении он должен давать класс соответствующей ссылке.
|
Цитата:
А тогда уже искать в меню соответствующий пункт. Посмотреть <div id="nav"> <a href="one" class="actual">one</a> <a href="two">two</a> <a href="three">three</a> </div> <div class="scroll selected" id="one">one</div> <div class="scroll" id="two">two</div> <div class="scroll" id="three">three</div> $('#nav a').click(function() { var id = $(this).attr('href'); // идентификатор блока с нужным якорем var y = $('#'+id).offset().top; // координаты начала блока $('body').animate({scrollTop:y}, 'slow'); // катимся к якорю + инициируем скроллинг return false; // отмена стандартного действия (перехода по ссылке) }); var lastID; // для id последнего посещённого блока, которому сменили класс var elemID; // для id текущего блока, которому будем добавлять класс $(window).scroll(function() { var yDoc = $(document).scrollTop(); // координаты текущего скроллинга по вертикали $('.scroll').each(function() { // прогуляемся по блокам (надеюсь их немного) var yElem = $(this).offset().top; // координаты позиции каждого блока по вертикали if (yDoc >= yElem && yDoc < (yElem+50)) { // если верх блока достиг верха страницы + запас 50px elemID = $(this).attr('id'); // id блока которому будем добавлять класс if (elemID != lastID) { // меняем класс только один раз для текущего блока (а не каждый пиксель скроллинга) lastID = elemID; // запоминаем, что здесь класс мы уже добавили mark($('#nav a[href='+elemID+']'), $(this)); // смена классов для блока и пункта меню } } }); }); function mark(nav, elem) { // функция смены классов $('#nav a').removeClass('actual'); nav.addClass('actual'); $('.scroll').removeClass('selected'); elem.addClass('selected'); } |
Большое спасибо за помощь, но я что-то затрудняюсь подключить скрипт. Мне на самом деле нужно чтобы только ссылка класс получала, вписал код так:
var lastID; // здесь будем хранить id последнего посещённого блока, которому сменили класс $(window).scroll(function() { var yDoc = $(document).scrollTop(); // координаты текущего скроллинга по вертикали $('.scroll').each(function() { // прогуляемся по блокам (надеюсь их немного) var yElem = $(this).offset().top; // координаты позиции блока по вертикали if (yDoc >= yElem && yDoc < (yElem+50)) { // диапазон между верхом блока + запас (если скроллинг быстрый) var id = $(this).attr('id'); if (id != lastID) { // для каждого блока меняем класс только один раз, нечего повторяться повторяться lastID = id; // запоминаем, что здесь класс мы уже добавили mark($('li a[href='+id+']'); // смена классов для блока и пункта меню } } }); }); function mark(nav) { // функция смены классов $('li a').removeClass('selected'); nav.addClass('selected'); } может где-то ошибся или какую-то конкретную библиотеку jquery подключить надо ? (все соответствующие классы прописал) |
Версия фреймворка в данном случае не важна, скорее всего Ваш html отличается от моего примера.
Обратите внимание на .css в примере. Класс, которым подсвечиваем ссылки в меню, имеет !important Сначала нужно понять, как работает данная реализация: 1. ловим событие $(window).scroll() 2. на каждой итерацию (каждый пиксель скроллинга) получаем текущую позицию прокрутки документа $(document).scrollTop() 3. на каждой итерации также проверяем, не совпадает ли позиция прокрутки документа с позицией каждого из элементов, но... 4. для этого (если элементов много) проходим по элементам циклом и работаем с каждым 5. для каждого элемента смотрим его положение в документе $(element).offset().top 6. сравниваем наши пункты 2. и 5.: if ($(document).scrollTop() >= $(element).offset().top) {...} 7. но при быстром скроллинге скрипт может не успеть отловить совпадение, поэтому расширяем пункт 6. и добавляем в if (...) вторую границу диапазона (50px от верхней границы элемента): && $(document).scrollTop() < ($(element).offset().top + 50) 8. если условие выполнилось, смотрим id элемента, с которым работаем в данный момент в цикле: $(element).attr('id') 9. используем переменные (lastID, elemID) чтобы лишний раз не добавлять класс ссылке в меню 10. находим в меню ссылку, атрибут которой соответствует id нашего элемента: $('menu a[href='+$(element).attr('id')+']') 11. присваиваем ссылке в меню класс, предварительно убрав класс у остальных ссылок. Упростил пример: Посмотреть . |
Большое спасибо, заработало) только одна проблема - класс ссылкам передаётся только при обратном скроллинге, т.е. снизу вверх, с чем это связано?
|
Иззет,
Сложно сказать, не увидев Вашего кода. Покажите всю страницу (html, css, js) в песочнице: http://learn.javascript.ru/play |
В вашем последнем примере, "Упростил пример: Посмотреть" тоже есть эта проблема, попробуйте вручную прокрутить вниз и, прокручивая сверху вниз, можно увидеть, что ссылке "two" класс "actual" не даётся.
|
Проверил в Safari, Chrome, Firefox, Opera - работает, каждая ссылка получает свой класс.
К сожалению в IE проверить не могу, т.к. Mac OS X. Хм... чтоб понять в чём дело, попробуйте: 1. прокручивать медленнее или быстрее. 2. увеличить интервал захвата, не 50 а например 100, возможно, скрипт не успевает совершить проверку при быстром скроллинге. |
Часовой пояс GMT +3, время: 15:03. |