Maintain scrollTop while inserting new sections ab

2019-02-06 07:47发布

问题:

Here's one for the real JQuery UI geniuses: We have a extremely long form with sections loaded on demand (e.g. when an index/navigation is clicked, or as we scroll near the edges of the current section).

When I load sections below the currently viewed section, this does not affect the current scrolling (i.e. scrollTop) position, but when I insert new sections above the current viewed section it of course pushes the viewed content down.

We need to maintain the scrollTop position relative to the current section. We also need to avoid the display jumping/glitching while the adjustments are made.

Options we are considering:

  1. Load the content and adjust the scrollTop position by the height of the loaded item (this will probably glitch badly as the DOM change is potentially much slower than the scrollTop adjustment).
  2. Load the new section offscreen, measure the height. Then insert the section and adjust the scrollTop by that amount (probably still glitch because of the DOM update).
  3. Set the section to be loaded to a large fixed height (e.g. 100/1000 pixels) and adjust the scrollTop to match so the current view does not move. Load the content into that section, then measure the actual new content height and remove the fixed height while adjusting the scrollTop to match the actual height.
  4. Don't use traditional scrolling, but write a custom scroller that maintains its own relative offsets and moves existing sections apart to fit new ones. The problem then becomes writing a custom scrollbar replacement (for something like nicescroll which we are using).
  5. Temporarily change the position of the current viewed section(s) to absolute (position calculated from the screen offset) to take it out of the flow. Update the parent scrolling window content behind it and then make the viewed section(s) relative again after recalculating the new scrollTop.
  6. Something else we have not thought of?

I would like some suggestions from anyone that has actually had to solve this problem. It is important that the screen not glitch, so syncing scrollTop to a slow DOM update should be avoided.

Suggestions or comments on the proposed solutions? Is there a scroll replacement that would do this already?

If you can't solve it, but think it is worth solving, consider upvoting so I can put a large bounty on it! :)

回答1:

Update 4 Sep 13

Option 4 turns out to be too slow in practice once you have to take into account things like auto-scrolling to keep focused controls onscreen.

It turns out Option 1 will work so long as you do the following:

  • Add top and bottom fillers (e.g. empty divs) so that the browser accepts the larger pane (margins are not taken into account by the browser's auto-scrolling) and you can't scroll below scrollTop 0 (no negative scrollTop in browsers).
  • When inserting content, first adjust the position of only items that are affected (i.e. above or below the target position in the view.
  • Once the adjustments are made change the position of all items (by stacking them from 0 again) and change the scrollTop to match. If there are only a few dozen items or less this will not glitch, so I strongly recommend having larger containers at the top level (like sections) that need to be scrolled, while their content remains relative.

Option 1 has the advantage that it does not fight the browser's native auto-scrolling when you change focus (e.g. tab) between items. This has turned out to be the best practical solution and has allowed us to produce a "very long" form consisting of dozens of dynamically loaded sections (loaded via navigation links, or via their proximity to viewport) and it works amazing well. Conga indeed!

Early testing:

Initially we went with option 4: We have created our own scrolling and we layout the items, absolutely positioned, within a relative parent.

When items change size the positions of item above or below are recalculated (depending on where they were relative to the viewport). This content change can be triggered by an Ajax load or manual change of size.

To cater for manual scrolling we are using MouseWheel.js and we are capping the scroll so that the extents of the first and last items are restricted by the top and bottom 25% of the viewport.

As the JQuery add-in "lines up" content, one after the other, we have decided to call it Conga. :)