История хэш-обмена прерывает iScroll

#javascript #jquery #iscroll

#javascript #jquery #iscroll

Вопрос:

Я создал следующее приложение, используя iScroll: http://preview.na-software.co.uk/Demo/FutureLearning4/#/section-0

Когда пользователь щелкает влево и вправо или щелкает стрелки в нижних углах, приложение перемещает разделы содержимого. Оно обновляет историю, изменяя хэш, Чтобы пользователь мог переходить к другим разделам и добавлять в них закладки и т. Д.

Однако! Если вы получаете доступ к хэшу, например: http://preview.na-software.co.uk/Demo/FutureLearning4/#/section-2 а затем перейдите по нескольким разделам, а затем используйте кнопки назад, возникают две проблемы:

1.) Он прокручивается до первого экрана (даже если currentSection он правильный, и iScroll указал правильный раздел).

2.) Если вы нажмете кнопку назад или вперед несколько раз, вы остановите анимацию и заставите ее запутаться и застрять между двумя разделами.

Изучив код и увидев, что правильные индексы и элементы передаются в iScroll при hashchange, а консоль выводит из системы смещения, я обнаружил, что проблема вызвана тем, что смещения установлены неправильно… однако простое выполнение refresh() не решит проблему, так как затем сбросит позицию.

Кто-нибудь может увидеть, в чем проблема, или найти способ исправить это?

Я должен отметить, что эта ошибка возникает ТОЛЬКО в том случае, если вы заходите в приложение по URL-адресу, который не является разделом 0, а затем прокручиваете приложение. Это потому, что смещения будут созданы правильно вашими взаимодействиями. Но если вы перейдете на URL, подобный разделу 3, то смещения будут неверными, и поэтому хэш-изменения будут работать некорректно, если это имеет смысл.

Метод hashchange выглядит следующим образом:

 // handle hashchange events
$(window).hashchange( function(){

    // read the hash to find out what the new section number is
    var nums = location.href.match(/(section)-d /g).map(
        function(x){ return  x.replace(/D/g,"") }
    );
    // set currentSection
    currentSection = nums[0];

    // if the hashchange was called by user scrolling
    if(hashCalledByScroll){
        // no need to anything as they have already updated hash and scrolled
        hashCalledByScroll = false;
    } else {
        // find the section to scrollTo
        sectionToScrollTo = $('#horizontal > .sections > .section').eq(currentSection).attr('id');
        // tell iscroll to scroll to the section
        horizontal.scrollToElement( '#'   sectionToScrollTo, null, null, true );
    }

    // hide the menu on hashchange
    hideMenu();

});
 

Ответ №1:

Тестируя ваш сайт, я заметил следующее: всякий раз, когда я захожу на сайт через раздел-3, а затем ввожу URL-адрес для раздела-2, навигация вместо этого отправляет меня в раздел-0.

Я считаю, что это то же поведение, что и в 1).

Итак, я исследовал и пришел к следующему анализу:

В функции horizontal.scrollToElement( '#' sectionToScrollTo, null, null, true ) iScroll извлекает utils.offset(el) [iScroll.js#772] для данного el элемента. Это смещение сообщает ему, где находится элемент для прокрутки.

iScroll просматривает элемент и все его родительские значения offsetParents, чтобы сложить их смещения. Вот где все ломается: <div class="sections"> имеет отрицательное смещение к своему родительскому элементу, которого, по-моему, у него не должно быть.

Это, в свою очередь, приводит к путанице в scrollTo -coordinates .

Чтобы понять, о чем я говорю: document.querySelector('.sections').offsetLeft

Все это было просто анализом. Мой подход к исправлению этого состоял бы в том, чтобы избегать scrollToElement() и вместо этого использовать scrollTo() :

     ...
    } else {
        // find the section to scrollTo
        sectionToScrollTo = $('#horizontal > .sections > .section').eq(currentSection).attr('id');
        // tell iscroll to scroll to the section
        var posLeft = -$('#'   sectionToScrollTo)[0].offsetLeft;
        var posTop = -$('#'   sectionToScrollTo)[0].offsetTop;
        horizontal.scrollTo(posLeft, posTop, 1000);
    }
    // hide the menu on hashchange
    hideMenu();
});
 

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

Около 2) Я не уверен, что с этим можно что-то сделать. Быстрое переключение приводит к разрыву множества каруселей. Возможно, отложенный обратный scrollEnd вызов, проверяющий правильность текущего состояния.

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

Надеюсь, это поможет.

Комментарии:

1. Не могли бы вы собрать скрипку, чтобы объяснить это? Спасибо за помощь.

2. Я пришел к тому же выводу. Я думаю, что наименее проблематичным способом исправить это было бы вычислить местоположения самостоятельно.

Ответ №2:

Найдено не лучшее решение, и оно не решает основную проблему, но оно работает.

 $(window).hashchange(function () {
    if (hashCalledByScroll) {
        hashCalledByScroll = false;
    } else {
        var hpage = window.location.hash;
        var hpage = hpage.replace('#/section-', ''); //get number of target page
        var cpage = currentSection; //number of current page
        var count = parseInt(hpage) - parseInt(cpage); //difference
        while (count > 0) { //if difference positive: go forward count-times
            horizontal.next();
            count--;
        }
        while (count < 0) { //if difference negative: go backward count-times
            horizontal.prev();
            count  ;
        }
    }
    hideMenu();
});
 

СКРИПКА

Комментарии:

1. Если это работает (еще не полностью протестировано), что вы имеете в виду, что это не решает основную проблему? Спасибо.

2. Я имею в виду, что это решение решает вашу проблему с кнопкой возврата истории, но оно не решает конфликт iScroll с хэшем