vue组件实现列表自动无限循环的方法

 更新时间:2023年11月14日 09:35:55   作者:The ever Boy  
最近刚好有个功能需要实现列表的无限循环滚动,这篇文章主要给大家介绍了关于vue组件实现列表自动无限循环的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

前述:

用过vue-seamless-scroll插件,手动滚动列表到底部出现了空白现象,某些表现不符合项目场景,故自己写了一个自己用的组件,如果有人需要可以直接拿去用,如有不足请指教勿喷!

主要功能:

  • 列表自动无限循环滚动
  • 鼠标移入停止滚动,移出继续滚动
  • 待滚动内容高度未铺满并超过容器高度时不滚动
  • 支持滚动速度、单次滚动时间间隔、单次滚动高度,三个参数控制
  • 可自己手动滚动列表

效果图 :

组件代码: 

<template>
  <div class="scroll-outer" ref="outer" @mouseover="onMouseover" @mouseleave="onMouseleave">
    <div class="scroll-inner-box" ref="scrollBox">
      <div class="scroll-item-box" ref="scrollItemBox">
        <slot></slot>
      </div>
      <div v-if="showSecond" class="scroll-item-box">
        <slot></slot>
      </div>
    </div>
  </div>
</template>
  <script>
export default {
  name: "my-auto-scroll",
  props: {
    list: {
      type: Array,
      default: () => [
        { name: "张三1" },
        { name: "张三2" },
        { name: "张三3" },
        { name: "张三4" },
        { name: "张三5" },
        { name: "张三6" },
        { name: "张三7" },
        { name: "张三8" },
        { name: "张三9" },
        { name: "张三10" },
      ],
    },
    speed: {
      type: Number,
      default: 0.1,
    },
    //滚动作单步运动时的单纯运动距离
    singleHeight: {
      type: Number,
      default: 0,
    },
    //单步运动的时间间隔
    waitTime: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {
      rafId: null,
      y: 0,
      showSecond: false,
      controleHeight: 0,
    };
  },
  watch: {
    list: {
      handler(newVal) {
        var that = this;
        this.$nextTick(() => {
          console.log(newVal);
          if (newVal && newVal.length > 0) {
            let scrollBox = that.$refs.scrollBox;
            let outer = that.$refs.outer;

            if (this.myReq) {
              cancelAnimationFrame(this.myReq);
            }
            // 开启动画
            if (this.canRun()) this.reqAnimationFrame();
            // this.reqAnimationFrame();
            // 手动滚动到底部时滚动条重置到最上边,同时滚动盒子重置为top:0
            outer.addEventListener("scroll", function () {
              if (
                outer.scrollTop + outer.clientHeight + 4 >=
                outer.scrollHeight
              ) {
                outer.scrollTop = 0;
                that.y = 0;
                scrollBox.style.top = 0;
              }
            });
          }
        });
      },
      deep: true,
      immediate: true,
    },
  },
  mounted() {
    window.addEventListener("resize", this.listenResizeFn);
  },
  methods: {
    listenResizeFn() {
      cancelAnimationFrame(this.myReq);
      if (this.canRun()) this.reqAnimationFrame();
    },
    onMouseover() {
      clearTimeout(this.timer);
      cancelAnimationFrame(this.myReq);
    },
    onMouseleave() {
      if (this.canRun()) this.reqAnimationFrame();
    },
    canRun() {
      let scrollItemBox = this.$refs.scrollItemBox;
      let scrollBox = this.$refs.scrollBox;
      let outer = this.$refs.outer;
      // 开启动画条件:滚动盒子(scrollBox)高度高于外层容器(outer)高度
      if (outer.offsetHeight >= scrollItemBox.offsetHeight) {
        this.showSecond = false;
        outer.scrollTop = 0;
        this.y = 0;
        scrollBox.style.top = 0;
        return false;
      } else {
        this.showSecond = true;
        return true;
      }
    },
    //获取dom元素的高度:content+padding+margin+border
    getComputedHeight(dom) {
      let computedStyle = getComputedStyle(dom);

      let computedHeight =
        dom.offsetHeight +
        parseFloat(computedStyle.marginTop) +
        parseFloat(computedStyle.marginBottom);
      return computedHeight;
    },
    reqAnimationFrame() {
      //外层容器
      let outer = this.$refs.outer;
      //滚动盒子
      let scrollBox = this.$refs.scrollBox;
      //滚动盒子下边的第一个scroll-item-box,
      let scrollItemBox = this.$refs.scrollItemBox;

      //滚动速度
      this.speed = this.speed > 1 ? 1 : this.speed < 0 ? 0.1 : this.speed;

      //取第一个scrollItemBox高度
      let definedHeight = this.getComputedHeight(scrollItemBox);
      //持续滚动
      this.y = this.y + this.speed;
      scrollBox.style.top = -this.y + "px";

      //====添加滚动间隔控制====开始
      if (this.singleHeight >= 20 && this.waitTime > 500) {
        if (this.controleHeight >= this.singleHeight) {
          cancelAnimationFrame(this.myReq);
          this.controleHeight = 0;
          this.timer = setTimeout(() => {
            if (this.canRun) this.reqAnimationFrame();
          }, this.waitTime);
          return;
        } else {
          // 一次移动高度未达到指定距离继续执行动画
          this.controleHeight += this.speed;
        }
      }
      //====添加滚动间隔控制====结束

      //当滚动到第一个scroll-item-box高度时scrollBox重置为top:0,视觉上是无缝滚动
      if (this.y >= definedHeight) {
        this.y = 0;
      }
      this.myReq = window.requestAnimationFrame(this.reqAnimationFrame);
    },
  },
  destroyed() {
    window.removeEventListener("resize", this.listenResizeFn);
    cancelAnimationFrame(this.myReq);
    if (this.timer) clearTimeout(this.timer);
  },
};
</script>
  <style lang="scss">
.scroll-outer {
  height: 100%;
  overflow-x: hidden;
  position: relative;
  &::-webkit-scrollbar {
    width: 0.3vw;
  }
  &:hover::-webkit-scrollbar-track {
    -webkit-box-shadow: inset 0 0 0.1vw rgba(0, 0, 0, 0.3);
    border-radius: 0.1vw;
    background-color: #295099;
    opacity: 1;
    // display: none;
  }
  &:hover::-webkit-scrollbar-thumb {
    opacity: 1;
    border-radius: 0.1vw;
    -webkit-box-shadow: inset 0 0 0.1vw rgba(0, 0, 0, 0.3);
    background-color: #0ba9ea;
  }
}
.scroll-inner-box {
  height: auto;
  position: absolute;
  width: 100%;
  top: 0;
  left: 0;
}
</style>
  
  

使用示例: 

import autoScroll from "@/components/autoScroll";
<autoScroll :list="list" :speed="0.5" :waitTime="2000" :singleHeight="100">
            <div class="t-item" v-for="(item,index) in list" :key="index">
              <div class="tvalue" style="flex: 0 0 30%;">{{ item.jgjc }}</div>
              <span class="tvalue">{{ item.total||'--' }}</span>
              <span class="tvalue" style="color:#0FCBDE">{{ item.ypc||'--' }}</span>
              <span class="tvalue" style="color:#F15730">{{ item.zlz||'--' }}</span>
              <span class="tvalue" style="color:#17DB68">{{ item.zlwc||'--' }}</span>
            </div>
          </autoScroll>

使用注意:

  • autoScroll容器默认是占外层容器宽高百分百,要自己在autoScroll外层加个容器
  • 参数waitTIme和singleHeight同时存在,才能出现滚动动画间隔执行的效果 
  • 样式用了sass,如果有问题可以去掉或者导入sass

总结 

到此这篇关于vue组件实现列表自动无限循环的文章就介绍到这了,更多相关vue列表自动无限循环内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Vue源码学习之数据初始化

    Vue源码学习之数据初始化

    这篇文章主要为大家介绍了Vue源码学习之数据初始化实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • vue2 element 弹出框拖拽会出现一层阴影问题解决方法

    vue2 element 弹出框拖拽会出现一层阴影问题解决方法

    这篇文章主要介绍了vue2 element 弹出框拖拽会出现一层阴影问题解决方法,因增加 draggable 属性导致我弹窗表单清空文本框时,从右向左选中字体会出现拖拽阴影效果,本文给大家介绍vue2 element 弹出框拖拽会出现一层阴影问题解决方法,感兴趣的朋友一起看看吧
    2024-01-01
  • vue-cli对element-ui组件进行二次封装的实战记录

    vue-cli对element-ui组件进行二次封装的实战记录

    组件类似于需要多个地方用到的方法,在Vue中组件就是一种复用(经常使用)一个功能的手段,下面这篇文章主要给大家介绍了关于Vue element ui二次封装的相关资料,需要的朋友可以参考下
    2022-06-06
  • vue中slot(插槽)的介绍与使用

    vue中slot(插槽)的介绍与使用

    这篇文章主要给大家介绍了关于vue中slot(插槽)的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用vue具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-11-11
  • vue中父子组件的参数传递和应用示例

    vue中父子组件的参数传递和应用示例

    这篇文章主要介绍了vue中父子组件的参数传递和应用示例,帮助大家更好的理解和使用vue框架,感兴趣的朋友可以了解下
    2021-01-01
  • Vue中搭配Bootstrap实现Vue的列表增删功能

    Vue中搭配Bootstrap实现Vue的列表增删功能

    日常开发中,我们可以用 “拿来主义” 借助Bootstarp现成的一些样式,快速生成我们想要的页面布局,避免书写大量的HTML和CSS代码,省下了许多不必要的时间,可以直接搭配vue使用
    2022-11-11
  • 如何在Vue中使localStorage具有响应式(思想实验)

    如何在Vue中使localStorage具有响应式(思想实验)

    这篇文章主要介绍了如何在Vue中使localStorage具有响应式,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • vue更多筛选项小组件使用详解

    vue更多筛选项小组件使用详解

    这篇文章主要为大家详细介绍了vue更多筛选项小组件的使用方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • 解决Vue前后端跨域问题的方式汇总

    解决Vue前后端跨域问题的方式汇总

    这篇文章主要介绍了解决Vue前后端跨域问题的多种方式,本文主要介绍借助解决Vue前后端跨域问题的几种方式,将会使用axios进行请求需要的朋友可以参考下
    2022-11-11
  • vue长按事件和点击事件冲突的解决

    vue长按事件和点击事件冲突的解决

    这篇文章主要介绍了vue长按事件和点击事件冲突的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10

最新评论