Необъяснимое поведение прокрутки при использовании homekey
Добрый день! Помогите разобраться в одной проблеме. Моя голова уже треснула от напруги и мозг булькает от перегрева... Букаф будетЬ мноХА((((
Возникла необходимость сделать отображение данных по мере прокрутки области просмотра (данные есть сразу все в памяти и на сервер нет смысла обращаться). Контейнер заранее неизвестен, однозначно известно лишь, что это могут быть совершенно разные контейнеры (table, div, p). Физический размер контейнера также заранее неизвестен и должен подстраиваться под своего родителя. Из-за потенциально непредсказуемого размера данные в контейнере должны находиться только те, которые отображаются пользователю. Остальные данные из него выгружаются в случае выбытия за пределы области просмотра. Размер DOM-элементов, выводящих данные, не должен иметь никаких ограничений, т.е. он может быть меньше (существенно или несущественно), равен или больше (существенно или несущественно) размера области просмотра. При этом не должно быть ситуации, что какая-то часть элемента недоступна пользователю, поскольку скроллинг вызывает загрузку другого элемента вместо прокрутки данного.
В принципе, в сети есть много плагинов с отображением только элементов, относящихся к области просмотра в данный момент. Меня они не устроили по ряду весомых причин. Не важно, почему. Вопрос не об этом.
Я реализовал иной алгоритм: в начале я загружаю столько элементов, чтобы все кроме последнего хотя бы частично были в области просмотра, а последний - за областью просмотра. Такой подход позволяет не думать о размерах отображаемых элементов - может поместится только один в области просмотра, да и то не полностью, а может 33. Далее по мере прокрутки я подгружаю с той стороны, куда прокручиваю, новые элементы так, чтобы один последний по возможности выходил за область просмотра. С обратной стороны области просмотра элементы, полностью вышедшие за пределы области просмотра я удаляю из DOM-дерева. При этом элементы с верхней стороны области просмотра я компенсирую padding'ом. Получается всё так, как мне нужно. Мышью скроллится хорошо - хоть маленькие, хоть большие элементы. Клавишами PageUp, PageDown, End - тоже всё здорово. А вот с клавишей Home возникли проблемы, которые прошу помочь разобрать и задать вектор для решения.
Что есть - я загрузил в контейнер с высотой 630px сотню элементов (пока высота всех одинакова 392px). Далее я через End пролистываю до конца. После этого я начинаю клавишей Home двигаться в начало. И в непредсказуемый момент происходит резкий возврат сразу к первому элементу. Я начал разбираться и обнаружил, что определенные изменения приводят к повторному автоматическому событию скроллинга:
1) При возникновении события скроллинга контейнер сразу получает новый scrollTop, а потом уже выполняется callback. Я загружаю новый элемент, выгружаю с другой стороны ненужный элемент. Таким образом получается, что дочерний элемент в области просмотра, на котором "зафиксировался" скроллинг, смещается, что приводит по факту к изменению scrollTop для области просмотра. Эту проблему я вроде как решил, фиксируя scrollTop до момента изменения DOM-дерева и восстанавливая его после каждого append
2) DOM-элементы имеют scrollHeight. По мере изменения DOM-дерева этот параметр меняется, также вызывая за собой событие скроллинга. При этом scrollTop может не меняться. Это я и использовал, чтобы отсечь данную проблему.
Но все равно по мере прокрутки через Home происходит резкое и непредсказуемое (т.е. каждый раз в различных точках - то сразу, то по прошествии нескольких Home) уменьшение scrollTop области просмотра в несколько этапов до нуля
Я пытался разобраться, какие именно еще события могут приводить к скроллингу, но пока понять не удалось. Я пытался найти проблему в своей "математике" - может где-то что-то не учел. Я логировал все параметры области просмотра до и после функции-обработчика, но параметры были идентичными. Единственное, если теоретически какие-то манипуляции могли привести к тому, что эти изменения возникают уже после функции-обработчика где-то в глубинах ядра JS... Я уже рисовал "покадрово" происходящее. Я пробовал при прокрутке по Home не убирать нижние элементы, чтобы не менять scrollHeight области просмотра. Это не помогло. Я не могу объяснить, как именно клавиша Home решает, на сколько нужно прокрутить область просмотра - некоторые изменения scrollTop превышают 7000px при том, что элементов при указанных размерах не более 5, т.е. не более 2000px. Я не могу понять, почему каждый раз Home ведет себя по-разному, т.е. при одинаковых начальных условиях (одинаковый scrollTop, два элемента по 392px, 630px область просмотра,) я получаю неодинаковое изменение scrollTop.
Не понимая, где в коде может быть ошибка, я решил посмотреть, как выглядит контейнер после такой резкой прокрутки - быть может натолкнет на какую-нибудь мысль. Я переписал код так, что при резком изменении scrollTop по сравнению с предыдущим состоянием ничего типа не выполнять и выйти из функции-обработчика. Каково было мое удивление, когда этот "хак" сработал и не стал менять DOM-дерево, но при этом событие скроллинга продолжило выстреливать, пока прокрутка не дошла до нуля! Т.е. DOM-дерево не менялось, не менялись свойства его элементов, а скроллинг почему-то генерировался!
Ситуация такая в хроме. Мозилла такую-же проблему показала. Что стоит также отметить - как я сказал, я занимал место выгруженных из начала очереди элементов padding'ом, т.е. контейнер реально растягивался. Однако ни разу Home не приводил при первом же нажатии к обнулению scrollTop области просмотра, хотя нередко и первое нажатие Home приводило к последовательному уменьшению этого показателя до нуля...
Фуф... вот такая ситуация. Люди, опытные в гадании без кофейной гущи, подкиньте, пожалуйста, догадок, объясняющих такое поведение скроллинга при использовании Home
|