至暗时代
  • 5
  • 新人请关照

vue轮播图插件,知道它的原理是在前后各加了一个img,不知道在哪实现了前后各插一个img的片段,请前辈解惑

这是APP只有5个图
image.png
这是ITEM
image.png

slider html部分
image.png


export default {
  name: 'ic-slider',
  props: {
    autoplay: Number,
    showIndicators: {
      type: Boolean,
      default: true
    },
    duration: {
      type: Number,
      default: 500
    }
  },
  data() {
    return {
      width: 0,
      offset: 0,
      startX: 0,
      startY: 0,
      active: 0,
      deltaX: 0,
      swipes: [],
      direction: '',
      currentDuration: 0
    };
  },
  mounted() {
    this.initialize();
    // 监听 resize事件,改变窗口重新初始化
    window.addEventListener('resize', () => {
        this.initialize();
    })
  },
  destroyed() {
    clearTimeout(this.timer);
  },
  watch: {
    swipes() {
      this.initialize();
    }
  },
  computed: {
    count() {
      return this.swipes.length;
    },
    trackStyle() {
      return {
        paddingLeft: this.width + 'px',
        width: (this.count + 2) * this.width + 'px',
        transitionDuration: `${this.currentDuration}ms`,
        transform: `translate3d(${this.offset}px, 0, 0)`
      };
    },
    activeIndicator() {
      return (this.active + this.count) % this.count;
    }
  },
  methods: {
    initialize() {
      clearTimeout(this.timer);
      this.width = this.$el.getBoundingClientRect().width;
      this.active = 0;
      this.currentDuration = 0;
      this.offset = this.count > 1 ? -this.width : 0;
      this.swipes.forEach(swipe => {
        swipe.offset = 0;
      });
      // this.autoPlay();
    },
    onTouchStart(event) {
      clearTimeout(this.timer);
      this.deltaX = 0;
      this.direction = '';
      this.currentDuration = 0;
      this.startX = event.touches[0].clientX;
      this.startY = event.touches[0].clientY;
      if (this.active <= -1) {
        this.move(this.count);
      }
      if (this.active >= this.count) {
        this.move(-this.count);
      };
      // console.log('start:'+this.deltaX)
      console.log('active:'+this.active)
    },
    onTouchMove(event) {
      this.direction = this.direction || this.getDirection(event.touches[0]);
      if (this.direction === 'horizontal') {
        event.preventDefault();
        this.deltaX = event.touches[0].clientX - this.startX;
        this.move(0, this.range(this.deltaX, [-this.width, this.width]));

        // console.log(this.deltaX+'deltaX'+'active:'+this.active);
      }
    },
    onTouchEnd() {
      if (this.deltaX) {
        this.move(Math.abs(this.deltaX) > 50 ? (this.deltaX > 0 ? -1 : 1) : 0);
        this.currentDuration = this.duration;
      }
      console.log(this.deltaX)
      // this.autoPlay();
    },
    move(move = 0, offset = 0) {
      const { active, count, swipes, deltaX, width } = this;
      if (move) {
        if (active === -1) {//初始值
          swipes[count - 1].offset = 0;
        }
        swipes[0].offset = active === count - 1 && move > 0 ? count * width : 0;
        this.active += move;
      } else {
        if (active === 0) {//第一个
          swipes[count - 1].offset = deltaX > 0 ? -count * width : 0;
        } else if (active === count - 1) {//最后一个
          swipes[0].offset = deltaX < 0 ? count * width : 0;
        }
      }
      this.offset = offset - (this.active + 1) * this.width;
      // console.log(this.swipes.length+'===length')
    },
    autoPlay() {
      const { autoplay } = this;
      if (autoplay && this.count > 1) {
        clearTimeout(this.timer);
        this.timer = setTimeout(() => {
          this.currentDuration = 0;
          if (this.active >= this.count) {
            this.move(-this.count);
          }
          setTimeout(() => {
            this.currentDuration = this.duration;
            this.move(1);
            this.autoPlay();
          }, 30);
          console.log(this.count+'   '+this.width)
        }, autoplay);
      }
    },
    getDirection(touch) {
      const distanceX = Math.abs(touch.clientX - this.startX);
      const distanceY = Math.abs(touch.clientY - this.startY);
      return distanceX > distanceY ? 'horizontal' : distanceX < distanceY ? 'vertical' : '';
    },
    range(num, arr) {
      return Math.min(Math.max(num, arr[0]), arr[1]);
    }
  }
};
</script>
阅读 1.2k
评论
    3 个回答
    redbuck
    • 1.2k

    仔细看了下,这个实现很巧妙,他没有在前后添加图片。

    我描述下他的做法。
    [0],1,2,3,4中括号表示视口,即当前看见0。

    如果此时从左向右滑动(slider整体移动),将4的transform设置为-count * width,即移到0的左侧,使用户可以看到4从左侧出现;反之4恢复translate(0);
    最右侧同理。

    具体实现代码如下

        if (active === 0) {
          swipes[count - 1].offset = deltaX > 0 ? -count * width : 0;
        } else if (active === count - 1) {
          swipes[0].offset = deltaX < 0 ? count * width : 0;
        }
    评论 赞赏
      Riant
      • 428

      组件ic-slider的template部分呢?

      评论 赞赏

        正常排版
        在第一个往右的托的时候, 把最后一个移动到第一个的前面。
        在最后一个往左的托的时候, 把第一个移动到最后一个的后面。
        过渡的时候也是这样,在合适的地方触发重排就可以了,动作结束后恢复原位置

        评论 赞赏
          撰写回答

          登录后参与交流、获取后续更新提醒