layout-scroll.vue 2.67 KB
<template>
  <div class="layout-scroll">
    <div class="layout-scroll-main" ref="scroll">
      <div class="scroll-body" :style="{'minHeight': wrapHeight + 'px'}">
        <slot></slot>
      </div>
      <div v-if="loading && !loading.hide" class="loading">
        <p v-if="loading.noMore" class="load-text">{{loading.noMoreText || '没有更多了'}}</p>
        <Loading v-else :size="20"></Loading>
      </div>
    </div>
  </div>
</template>

<script>
import {throttle} from 'lodash';
import {Loading} from 'cube-ui';

const EVENT_SCROLL = 'scroll';

export default {
  name: 'LayoutScroll',
  data() {
    return {
      noMore: false,
      wrapHeight: 0,
    };
  },
  props: {
    loading: Object
  },
  mounted() {
    this.wrapHeight = this.$el.offsetHeight;

    this._forceUpdate = throttle(this.forceUpdate.bind(this), 500);
    this._onPullingUp = throttle(this.onPullingUp.bind(this), 1000);

    let supportsPassive = false;

    try {
      const opts = Object.defineProperty({}, 'passive', {
        get() {
          supportsPassive = true;
          return true;
        }
      });

      window.addEventListener('test', null, opts);
    } catch (e) {} //eslint-disable-line
    this.$el.addEventListener(EVENT_SCROLL, this.onScroll, supportsPassive ? { passive: true } : false);
  },
  beforeDestroy() {
    this.$el.removeEventListener(EVENT_SCROLL, this.onScroll);
  },
  methods: {
    scrollTo() {
      let top = arguments[1] || arguments[0];

      this.$el.scrollTop = Math.abs(top);
    },
    onScroll() {
      let top = this.$el.scrollTop;

      if (this.lastTop === top) {
        return;
      }

      this._forceUpdate();

      this.lastTop = top;
      this.$emit('scroll', {y: -top});

      this.scrollTimer && clearTimeout(this.scrollTimer);
      this.scrollTimer = setTimeout(this.onScrollEnd.bind(this), 400);
      if (!this.loading || !this.loading.noMore) {
        if (this.scrollHeight - top < this.$el.offsetHeight * 2) {
          this._onPullingUp();
        }
      }
    },
    getScrollTop() {
      return this.$el.scrollTop;
    },
    onScrollEnd() {
      this.$emit('scroll-end', {y: -this.$el.scrollTop});
    },
    onPullingUp() {
      this.$emit('pulling-up');
    },
    forceUpdate() {
      this.scrollHeight = this.$refs.scroll.offsetHeight;
    }
  },
  components: {
    Loading
  }
};
</script>

<style lang="scss" scoped>
.layout-scroll {
  height: 100%;
  overflow-x: hidden;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  position: relative;
  z-index: 0;
}

.layout-scroll-main {
  min-height: 100%;
}

.loading {
  padding: 20px 0;
  line-height: 40px;
  text-align: center;

  /deep/ .cube-loading-spinners {
    margin: auto;
  }
}
</style>