vue-affix icon indicating copy to clipboard operation
vue-affix copied to clipboard

scroll-affix breaks when the affix dynamically grows

Open 719media opened this issue 5 years ago • 4 comments

if you scroll-affix something that is smaller height than viewport (no scroll needed), scroll down slightly, and then dynamically grow it such that it becomes taller than the viewport, you won't be able to get the affix to scroll until you reach the top or bottom of the main content.

To see issue, use this: https://jsfiddle.net/dhab1z3e/1/

Scroll down a little, then click the "SHOW MORE BUTTON", then continue scrolling. Note that the affix does not scroll.

It works correctly if you SHOW MORE before scrolling, or return back to the top so that the affix position resets to normal and then begin scrolling again.

719media avatar Apr 16 '19 17:04 719media

Such a great description, thanks a lot for that, I'll take a look into the issue asap :)

eddiemf avatar Apr 16 '19 19:04 eddiemf

I don't think it should be the job of vue-affix to listen for height changes due to internal DOM changes. I mean, if you want to go down that route, great. However, alternatively, you could just have a method available to "refresh" the calculations.

I'm comparing your library to https://github.com/somewebmedia/hc-sticky They have a method called refresh which I can use when this happens.

Your library I tried calling onScroll, after my DOM change, which seems like the closest thing, but it did not work when the DOM changed (and the affix was partially scrolled).

I just wanted to propose a potential solution (basically to have a refresh method that is meant to be called anytime you want to recalibrate)

719media avatar Apr 18 '19 17:04 719media

Calling initScrollAffix followed by onScroll sort of fixes the problem... however, some jenk still occurs when you re-collapse, or open the content when it will have overspilled the bottom (e.g. scroll to the bottom of the reference, then open the content). example

https://jsfiddle.net/d178ogjh/1/

719media avatar Apr 18 '19 19:04 719media

Hi everyone, I know it's an old issue, but I stumbled upon a similar one and I think I have a decent solution.

A small addition to the data object

data() {
  return {
    ro: null,
    // ...
  };
},

Two additional methods:

// kind of a workaround
stick() {
  this.lastState = null;
  this.initScrollAffix();
  this.onScroll();
},
unstick() {
  this.removeClasses();
  this.$el.style = {};
}

Add (and remove) a ResizeObserver in the lifecycle hooks.

mounted() {
  // ...

  this.ro = new ResizeObserver(entries => {
    if (! this.scrollContainer || ! this.relativeElement) return;

    for (let entry of entries) {
      const elHeight = entry.target.clientHeight;
      const fullHeight = this.relativeElement.clientHeight;
      const scrollHeight = this.scrollContainer.innerHeight || this.scrollContainer.clientHeight

      if (elHeight < fullHeight && fullHeight > scrollHeight) {
        this.stick();
      } else {
        this.unstick();
      }
    }
  });

  this.ro.observe(this.$el);
},

beforeDestroy() {
  this.ro.unobserve(this.$el);

  this.unstick();
  this.scrollContainer.removeEventListener('scroll', this.handleScroll);
}

Let me know, if there is any interest in a PR.

Artem-Schander avatar Jan 15 '21 10:01 Artem-Schander