瀑布流加载的实现

77 阅读1分钟

下拉加载

父组件

<template>
  <c-scroll 
    ref="cscroll"
    @requestData="requestData"
  >
    <template slot="list">
      <div v-for="item in list" :key="item" class="scroll-item">
        {{item}}
      </div>
    </template>
  </c-scroll>
</template>

<script>
import CScroll from "@/components/common/c-scroll";

export default {
  components: {
    CScroll
  },
  data() {
    return {
      list: [1,2,3,4,5,6,7,8,9, 10]
    };
  },
  methods: {
    requestData() {
      this.$refs.cscroll.setLoading(true);
      setTimeout(() => {
        this.$refs.cscroll.setLoading(false);
        if (this.list.length <= 10) {
          this.list = this.list.concat([11,12,13,14,15,16,17,18,19,20]);
        } else {
          this.$refs.cscroll.setOverflow(true);
        }
      }, 3000);
    }
  }
};
</script>

<style lang="scss" scoped>
  
  .scroll-item {
    height: 200px;
    margin-bottom: 10px;
  }
  
</style>

子组件

<template>
  <div
    class="scroll-c"
    @scroll="scrollFn"
  >
    <slot name="list"></slot>
    <div 
      v-for="item in list" 
      :key="item" 
      class="scroll-item">{{item}}</div>
    <van-loading v-if="loading" size="24px">加载中...</van-loading>
    <c-van-divider
      v-if="overflow"
      :className="'hr-top'"
      :text="`我是有底线的`"
    />
  </div>
</template>

<script>
/**
 * 使用此组件须知,scroll-c必须要有滚动条展示,
 * slot=list 里面的元素,必须具备 class="scroll-item"
 * 
 * 注意:this.loading = true的时候是节流的
*/
import VanLoading from "vant/lib/loading";
import "vant/lib/loading/style";
import CVanDivider from "@/components/common/c-hr/divider.vue";
import {debounce} from "@/lib/debounce";
export default {
  components: {
    VanLoading,
    CVanDivider
  },
  data() {
    this.scrollFnDebounce = debounce((top, offsetTop) => {
       if (top > offsetTop) {
          // 滚动条滚动到最后一个元素的出现位置
          this.requestData();
        }
    });
    return {
      overflow: false,
      loading: false,
      list: []
    };
  },
  methods: {
    setLoading(bool) {
      this.loading = bool;
    },
    setOverflow (bool) {
      this.overflow = bool;
    },
    requestData() {
      console.log("aaa");
      this.$emit("requestData");
    },
    scrollFn(e) {
      if (this.loading || this.overflow) { // this.loading 节流
        return;
      }
      // 获取滚动条位置
      const scrollTop = e.currentTarget.scrollTop;
      const clientHeight = e.currentTarget.clientHeight;
      const children = e.currentTarget.querySelectorAll(".scroll-item");
      if (children.length > 0) {
        const lastDom = children[children.length - 1];
        this.scrollFnDebounce(scrollTop + clientHeight, lastDom.offsetTop);
      }
    }
  }
};
</script>

<style lang="scss" scoped>
  .scroll-c {
    height: 100%;
    overflow-y: auto;
    position: relative;
    .scroll-item {
      // height: 200px;
      // margin-bottom: 10px;
      position: relative;
    }
    ::v-deep .van-loading {
      text-align: center;
      margin: 20px;
    }
  }
</style>

上拉加载,加载数据往前加的

父组件

<template>
  <c-scroll 
    ref="cscroll"
    @requestData="requestData"
  >
    <template slot="list">
      <div v-for="item in list" :key="item" class="scroll-item">
        {{item}}
      </div>
    </template>
  </c-scroll>
</template>

<script>
import CScroll from "@/components/common/c-scroll";

export default {
  components: {
    CScroll
  },
  data() {
    return {
      list: [1,2,3,4,5,6,7,8,9, 10]
    };
  },
  mounted() {
    this.$nextTick(() => {
      if (this.$refs.cscroll) {
        const scrollHeight = this.$refs.cscroll.getScrollHeight();
        console.log(scrollHeight, "scrollHeight");
        this.$refs.cscroll.scrollYTo(scrollHeight);
      }
    });
  },
  methods: {
    requestData() {
      this.$refs.cscroll.setLoading(true);
      setTimeout(() => {
        this.$refs.cscroll.setLoading(false);
        if (this.list.length <= 10) {
          const list = [11,12,13,14,15,16,17,18,19,20];
          list.forEach(item => {
            this.list.unshift(item);
          });
          this.$nextTick(() => {
            this.$refs.cscroll.scrollYTo(list.length * 200 - 40);
          });
        } else {
          this.$refs.cscroll.setOverflow(true);
        }
      }, 3000);
    }
  }
};
</script>

<style lang="scss" scoped>
  
  .scroll-item {
    height: 200px;
    margin-bottom: 10px;
  }
  
</style>

子组件

<template>
  <div
    ref="scrollC"
    class="scroll-c"
    @scroll="scrollFn"
  > 
    <div class="loading-top-c">
      <van-loading v-if="loading" size="24px">加载中...</van-loading>
    </div>
    <slot name="list"></slot>
    <div 
      v-for="item in list" 
      :key="item" 
      class="scroll-item">{{item}}</div>
  </div>
</template>

<script>
/**
 * 使用此组件须知,scroll-c必须要有滚动条展示,
 * slot=list 里面的元素,必须具备 class="scroll-item"
 * 
 * 注意:this.loading = true的时候是节流的
*/
import VanLoading from "vant/lib/loading";
import "vant/lib/loading/style";
// import CVanDivider from "@/components/common/c-hr/divider.vue";
import {debounce} from "@/lib/debounce";
export default {
  components: {
    VanLoading,
    // CVanDivider
  },
  data() {
    this.scrollFnDebounce = debounce((Num, scrollTop) => {
      console.log(Num, scrollTop, "scrollTop");
       if (scrollTop < Num) {
          // 滚动条滚动到最后一个元素的出现位置
          this.requestData();
        }
    });
    return {
      overflow: false,
      loading: false,
      list: []
    };
  },
  methods: {
    setLoading(bool) {
      this.loading = bool;
    },
    setOverflow (bool) {
      this.overflow = bool;
    },
    requestData() {
      console.log("aaa");
      this.$emit("requestData");
    },
    getScrollHeight() {
      return this.$refs.scrollC.scrollHeight;
    },
    scrollYTo(num) {
      this.$refs.scrollC.scrollTop = num;
    },
    scrollFn(e) {
      if (this.loading || this.overflow) { // this.loading 节流
        return;
      }
      // 获取滚动条位置
      const scrollTop = e.currentTarget.scrollTop;
      this.scrollFnDebounce(60, scrollTop);

    }
  }
};
</script>

<style lang="scss" scoped>
  .scroll-c {
    height: 100%;
    overflow-y: auto;
    position: relative;
    .loading-top-c {
      height: 64px;
    }
    .scroll-item {
      // height: 200px;
      // margin-bottom: 10px;
      position: relative;
    }
    ::v-deep .van-loading {
      text-align: center;
      margin: 20px;
    }
  }
</style>