5

I'm trying to make a little directive that will keep the div scrolled to the bottom if the div is currently scrolled to the bottom, but will not scroll to the bottom if the user scrolls up, but will continue to scroll down if scrolled back to the bottom, this is the bit of code I have so far

Vue.directive('scroller', {
  bind: function(el, bindings, vnode) {
  },
  componentUpdated: function(el, bindings, vnode) {
    console.log(el.scrollHeight - el.scrollTop, $(el).outerHeight())
    if (el.scrollHeight - el.scrollTop >= $(el).outerHeight()) {
      // scroll to bottom
    }

    // Leave the scroller alone
  }
});

This is what I get from the console log

bundle.js:8237 295 251.1875
bundle.js:8237 339 251.1875
bundle.js:8237 383 251.1875
bundle.js:8237 427 251.1875
bundle.js:8237 295 251.1875

if I scroll all the way to the bottom the closest I can get is 295, it starts off at

251 251.1875 but as soon as the overflow begins and it starts to scroll, it seems to stay at 295 being the closest I can get back to 251.

I got the calculation from

Detecting when user scrolls to bottom of div with jQuery

Community
  • 1
  • 1
Datsik
  • 14,453
  • 14
  • 80
  • 121

2 Answers2

1

If you want something a little simpler in Vue 2, add this method:

scrolledToBottom(event){
        var el = event.srcElement
        console.log(el.scrollTop + " " + el.scrollHeight + " " + el.clientHeight)
        if(!this.reachedBottom){
            if(el.scrollTop >= (el.scrollHeight - el.clientHeight)-100){
                this.reachedBottom = true
            }
        } 
    },

Then, on the element that's being scrolled, add an event listener:

<div @scroll="scrolledToBottom" style="overflow:scroll; max-height:500px;">
<!--content-->
</div>
Gabriel Garrett
  • 2,087
  • 6
  • 27
  • 45
-1

I think the delta you're having is because you have to take the div container height into your calculations.

Also I'm subtracting 50 to have the reactivation point a bit sooner. You can adjust this value. It's only there that the user must not scroll completely down to the end.

Please find a working demo below or in this fiddle.

Vue.directive('scroller', {
  bind: function(el, bindings, vnode) {
    this.manualScroll = false;
  },
  componentUpdated: function(el, bindings, vnode) {
    console.log('updated', el.scrollHeight - el.scrollTop); //$(el).outerHeight())
    if (el.scrollHeight - el.scrollTop >= el.clientHeight) {
      // scroll to bottom
      if (!this.manualScroll) {
        el.scrollTop = el.scrollHeight - el.clientHeight; // triggers scroll event
      }
    }
  },
  inserted: function(el) {
    el.scrollTop = el.scrollHeight - el.clientHeight;
    // console.log(el.scrollHeight)
    var self = this;
    el.addEventListener('scroll', function(evt) {
      console.log('evt', el.scrollTop);
      self.manualScroll = (el.scrollTop < el.scrollHeight - el.clientHeight - 50);
      console.log('manual scroll', self.manualScroll)
    })
  }
});

Vue.component('DynamicUpdates', {
  template: '<div class="dynamic-container" v-scroller><ul><li v-for="count in counter">{{count}}</li></ul></div>',
  props: {
    counter: Array
  },
  data: function() {
    return {
      updateInterval: null
    };
  },
  computed: {
    count: function() {
      return this.counter.length;
    }
  },
  mounted: function() {
    this.updateInterval = setInterval(this.update, 200);
  },
  methods: {
    update: function() {
      this.counter.push(this.count++);
    }
  },
  beforeDestroy() {
    clearInterval(this.updateInterval);
  }
})

new Vue({
  el: '#app',
  data: {
    counter: [],
    msg: 'hello world'
  }
})
.dynamic-container {
  width: 500px;
  height: 150px;
  overflow-y: scroll
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.js"></script>
<div id="app">
  <!--{{msg}}-->
  <button @click="counter=[]">
    restart
  </button>
  <dynamic-updates :counter="counter"></dynamic-updates>
</div>
AWolf
  • 8,770
  • 5
  • 33
  • 39