<template>
  <div class="bs-wrapper" ref="wrapper">
    <div class="scroller">
      <div class="pull-down-tips" v-if="pulldown">
        <div v-html="tipText"></div>
      </div>
      <slot> </slot>
      <div class="pull-up-tips" v-if="!loadOver && pullup">
        <div v-if="!isPullUpLoad" class="before-trigger">
          <span class="pul-lup-txt">加载更多</span>
        </div>
        <div v-else class="after-trigger">
          <span class="pull-up-txt">加载中...</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
import BScroll from "@better-scroll/core";
import PullDown from "@better-scroll/pull-down";
import Pullup from "@better-scroll/pull-up";
//注册插件
BScroll.use(PullDown);
BScroll.use(Pullup);

const PHASE: any = {
  moving: {
    enter: "enter",
    leave: "leave",
  },
  fetching: "fetching",
  succeed: "succeed",
};

const ARROW_BOTTOM = '<svg width="16" height="16" viewBox="0 0 512 512"><path fill="currentColor" d="M367.997 338.75l-95.998 95.997V17.503h-32v417.242l-95.996-95.995l-22.627 22.627L256 496l134.624-134.623l-22.627-22.627z"></path></svg>';
const ARROW_UP = '<svg width="16" height="16" viewBox="0 0 512 512"><path fill="currentColor" d="M390.624 150.625L256 16L121.376 150.625l22.628 22.627l95.997-95.998v417.982h32V77.257l95.995 95.995l22.628-22.627z"></path></svg>';
/**
 * @description: 滚动组件
 * @author:    ZPFly
 * @date:      2021/2/3 10:26
 */
@Component({
  name: "ScrollerView",
  components: {},
})
export default class ScrollerView extends Vue {
  /**
   * 开启横向滚动
   */
  @Prop({ default: false }) scrollX: boolean | undefined;
  /**
   * 滚动高度
   */
  @Prop({ default: 0 }) height: number | undefined;
  /**
   * 是否派发滚动到底部的事件，用于上拉加载
   */
  @Prop({ default: false }) pullup: boolean | undefined;
  /**
   * 是否派发顶部下拉的事件，用于下拉刷新
   */
  @Prop({ default: false }) pulldown: boolean | undefined;
  /**
   * 是否派发滚动事件事件
   */
  @Prop({ default: false }) listenScroll: boolean | undefined;
  /**
   * 刷新数据方法
   */
  @Prop({ default: () => {} }) refreshData: any | undefined;
  /**
   * 加载更多数据方法
   */
  @Prop({ default: () => {} }) loadData: any | undefined;
  /***/
  scroll: any | undefined;
  tipText = "";
  isPullUpLoad = false;
  loadOver = false;

  refresh() {
    setTimeout(() => {
      this.scroll.refresh();
    }, 100);
  }
  // 监听数据的变化，延时refreshDelay时间后调用refresh方法重新计算，保证滚动效果正常
  _initScroll() {
    if (!this.$refs.wrapper) {
      return;
    }
    // better-scroll的初始化
    this.scroll = new BScroll(this.$refs.wrapper as any, {
      probeType: 1,
      scrollX: this.scrollX,
      scrollY: !this.scrollX,
      preventDefault: false,
      pullUpLoad: true,
      pullDownRefresh: {
        threshold: 80,
        stop: 60,
      },
    });
    // 下拉刷新
    if (this.pulldown) {
      this.scroll.on("enterThreshold", () => {
        this.setTipText(PHASE.moving.enter);
      });
      this.scroll.on("leaveThreshold", () => {
        this.setTipText(PHASE.moving.leave);
      });
      this.scroll.on("pullingDown", () => {
        this.setTipText(PHASE.fetching);
        this.refreshData().then(() => {
          this.finishPullDown();
        });
      });
    } else {
      this.stopPullDown();
      this.scroll.on("scrollEnd", () => {
        this.finishPullDown();
      });
    }
    // 上拉加载
    if (this.pullup) {
      this.scroll.on("pullingUp", () => {
        this.isPullUpLoad = true;
        if(!this.loadOver) {
          this.loadData().then((loadOver: boolean) => {
            this.loadOver = loadOver;
            this.isPullUpLoad = false;
            this.scroll.finishPullUp();
            this.refresh();
          });
        }
      });
    }
    // 是否派发滚动事件
    if (this.listenScroll) {
      this.scroll.on("scroll", (pos: any) => {
        this.$emit("scroll", pos);
      });
    }
    this.refresh();
  }
  // 不用下拉刷新时，阻止下拉
  stopPullDown() {
    const scroller: any = this.$el.querySelector(".scroller");
    const hooks = this.scroll.scroller.actions.hooks;
    const top = scroller.getBoundingClientRect().top;
    hooks.on("beforeMove", (e: any) => {
      return scroller.getBoundingClientRect().top > top;
    });
  }
  finishPullDown() {
    this.setTipText(PHASE.succeed);
    this.scroll.finishPullDown();
    this.refresh();
  }
  setTipText(phase = PHASE.default) {
    const PULL_DOWN_TEXTS: any = {
      enter: `${ARROW_BOTTOM} 下拉刷新`,
      leave: `${ARROW_UP} 释放刷新`,
      fetching: "加载中...",
      succeed: "刷新成功",
    };
    this.tipText = PULL_DOWN_TEXTS[phase];
  }
  mounted() {
    this.initHeight();
    // 保证在DOM渲染完毕后初始化better-scroll
    this.$nextTick(() => {
      this._initScroll();
    });
  }
  // 初始化高度
  initHeight() {
    const el: any = this.$el;
    if (this.height) {
      el.style.height = this.height + "px";
    }
  }
}
</script>

<style lang="scss" scoped>
.bs-wrapper {
  position: relative;
  height: inherit;
  overflow: hidden;
}
.scroller {
  padding-bottom: 2px;
}
.pull-down-tips {
  position: absolute;
  width: 100%;
  padding: 20px;
  box-sizing: border-box;
  transform: translateY(-100%) translateZ(0);
  text-align: center;
  color: #999;
}
.pull-up-tips {
  padding: 10px;
  text-align: center;
  color: #999;
}
</style>
