dreipol/vue-ui

View on GitHub
src/mixins/scroll/index.js

Summary

Maintainability
A
35 mins
Test Coverage
import { mapActions, mapState } from 'vuex'
import throttle from 'lodash/throttle'
import bemMixin from '../bem'

const ROOT_CLASS = 'scroll-root'

export default {
  mixins: [bemMixin(ROOT_CLASS)],
  data() {
    return {
      scrollLockPosition: null,
    }
  },
  computed: {
    ...mapState('vue-ui/scroll', ['position', 'scrollbarWidth', 'isLocked']),
  },
  methods: {
    ...mapActions('vue-ui/scroll', ['setScroll']),
    throttledSetScroll: throttle(function troggledSetScroll() {
      this.setScroll()
    }, 100),
  },
  mounted() {
    this.setScroll()
    document.documentElement.classList.add(ROOT_CLASS)
    window.addEventListener('scroll', this.throttledSetScroll)
  },
  beforeDestroy() {
    window.removeEventListener('scroll', this.throttledSetScroll)
  },
  watch: {
    $route: {
      handler() {
        // NOTE: Don't reset scroll position after route change
        this.scrollLockPosition = 0
      },
    },
    isLocked: {
      handler(val) {
        const lockedClass = this.bemAdd('is-locked', null, ROOT_CLASS)

        document.documentElement.classList[val ? 'add' : 'remove'](lockedClass)
        document.body.style.top = val ? `${this.position * -1}px` : ''
        document.body.style.paddingRight = val ? `${this.scrollbarWidth}px` : ''

        if (val) {
          this.scrollLockPosition = this.position
        } else {
          // NOTE: Force a vuex update for all registered components
          if (document.body.scrollTop === this.scrollLockPosition) {
            window.scrollTo(0, this.scrollLockPosition + 1)
            this.setScroll()
          }

          window.scrollTo(0, this.scrollLockPosition)
          this.setScroll()
        }
      },
    },
  },
}