vue如何实现循环滚动,这个到最后会退到第一个?

dom部分pug模板
ul.list.ulScroll(:style="{ top }")
  li.item {{item}}
  
  private activeIndex:number=0;
  get top():string {
    return - this.activeIndex * 35 + 'px';
  }

  private mounted(): void {
    let _this = this;
    setInterval(function(){
      if(_this.activeIndex < _this.list.length-5) {
        _this.activeIndex +=1;
      } else {
        _this.activeIndex = 0;
      }
    }, 1000);
 }
 <style lang="styles">
 .rankingScroll
  height 175px
  overflow hidden
  position relative

  .ulScroll
    margin 0;
    position relative
    transition top 0.5s
    -webkit-transition top 0.5s
    
    .item
    display flex
    align-items center
    height 35px
    line-height:35px

 </style>
阅读 3.3k
1 个回答

轮播?

单向轮播的话,复制第一个到最后一个.

比如 [1],2,3将第一个复制到最后,变成:

[1],2,3,1滚动到索引为3时,将索引切换为0.
双向轮播同样,将最后一个复制到最前面,变成:
3,[1],2,3,1

[1]表示当前可见的元素

项目里找了个组件.

<template>
  <div class="roll-rank" :style="wrapStyle">
    <ul class="list" :style="{transform, transition}">
      <li class="item" v-for="item in list" :key="item.key" ref="item">
        <slot :data="item"></slot>
      </li>
    </ul>
  </div>
</template>

<script>
const sleep = time => new Promise(r => setTimeout(r, time));
export default {
  name: "roll-rank",
  props: {
    max: {
      type: Number,
      default: 5
    },
    options: {
      type: Array,
      required: true
    }
  },
  components: {},
  data() {
    return {
      times: 0, // 当前最顶部的索引
      wrapStyle: {
        height: "auto"
      },
      transform: "",
      transition: ""
    };
  },
  created() {
    this.play();
  },
  methods: {
    //  列表超出限定时,自动向上轮播
    async play() {
      while (this.max < this.options.length) {
        await sleep(1000);
        await this.next();
      }
    },

    // 让列表向上爬升一格
    async next() {
      this.times++;
      await this.slideTo(this.times * this.itemHeight);
      // 滚到最后一个时,重置并直接回到原位
      if (this.times === this.options.length) {
        this.times = 0;
        this.goTo(0);
      }
    },

    // 缓动
    async slideTo(distance, duration = 300) {
      this.transition = duration + "ms";
      this.goTo(distance);
      await sleep(duration);
      this.transition = "";
    },

    // 直达
    goTo(distance) {
      this.transform = `translate3d(0,-${distance}px,0)`;
    },

    // 获取一个元素的高度
    getStyle() {
      const item = this.$refs["item"];
      if (!item || !item.length) return;
      const height = (this.itemHeight = item[0].clientHeight);
      this.wrapStyle.height =
        height * Math.min(this.max, this.options.length) + "px";
    }
  },
  computed: {
    list() {
      // 列表超出限定时,将一部分补到底部
      if (this.options.length > this.max) {
        return [
          ...this.options,
          ...this.options
            .slice(0, this.max)
            .map(it => ({ ...it, key: it.key + Math.random() }))
        ];
      }
      return this.options;
    }
  },
  watch: {
    // 获取item的高度
    options: {
      handler() {
        this.$nextTick(() => {
          this.getStyle();
        });
      },
      immediate: true
    }
  }
};
</script>

<style lang="less" rel="stylesheet/less">
.roll-rank {
  overflow: hidden;
  .list {
    padding: 0;
    margin: 0;
    .item {
      padding: 0;
      margin: 0;
    }
  }
}
</style>

使用方式

// template
<RollRank :options="list">
    <template v-slot="props">
      <span>{{props.data.name}}</span>
    </template>
</RollRank>

// data
     list: [...Array(10)]
        .fill(0)
        .map((n, i) => ({ key: i, name: "苹果" + i, price: 100 * i }))

附一个在线DEMO

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题