swiper组件增加动画控制,更灵活

基于微博语法,
这里是组件使用代码
引入组件,组件的使用及属性方法在组件内部也进行了注释
originalData 数据
autoPlay 是否自动播放
interval 自动播放间隔时间
indicatorDots 是否显示指示点
indicatorColor 指示点颜色
indicatorActiveColor 当前选中的指示点颜色
current 当前的滑块是第几个 用法 :current.sync=‘current’,外部数据跟组件内部是同步的
vertical 滑动方向是否为纵向
@currentChange 轮播图改变时会触发 currentChange 事件,返回当前滑块为第几个
@moveTouchStart 滑动开始触发的方法
@moveTouchEnd 滑动结束触发的方法
@slideToNumber(index,isAnimation) 调取这个方法可以直接跳转到某一个滑块 index为要跳转的第几个滑块, isAnimation为是否需要动画

<template>
  <wbx-view class="" style="width: 100vw;height: 100vh;">
    <wbx-view style="margin-top: 100px; margin-left: 30px;margin-bottom: 20px;">
      <WBXswiper 
      :current.sync="current"
      :vertical="true"  
      :indicatorDots="true"  
      ref="seiperDom"  
      :autoPlay="true" 
      indicatorActiveColor="#fff" 
      indicatorColor="#c0c0c0" 
      :originalData="items"   
      @moveTouchEnd="end" 
      @moveTouchStart="start" 
      @currentChange="gaibian" 
      style="width: 300px;height: 300px;border-radius: 20px;">
        <template slot="swiperItem" slot-scope="scope">
          <wbx-image :src="scope.item.src" mode="scaleToFill" style="width:300px; height: 300px;" />
        </template>
      </WBXswiper>
    <wbx-view @click="add(99,true)" style="width: 30px;height:30px;background-color: red;">
      <wbx-text style="color:#000">99</wbx-text>
    </wbx-view>
    <wbx-view @click="add(1,true)" style="width: 70px;height:30px;background-color:rebeccapurple;">
      <wbx-text style="color:#000">1有效果</wbx-text>
    </wbx-view>
    <wbx-view @click="add(4,false)" style="width: 70px;height:30px;background-color: gold;">
      <wbx-text style="color:#000">4没效果</wbx-text>
    </wbx-view>
    <wbx-text style="width: 100px;height: 50px;color: red;border: 1px solid #000;">
      总数:{{items.length}}
    </wbx-text>
    </wbx-view>
	</wbx-view>
</template>

<script>
/**
 * @type WBXAppOption
 */
import WBXswiper from "../../commpents/WBXswiper/index.vue";
const pageOptions = {
  data() {
    return {
      items: [
          {
            src: 'res/001.jpg',
            txt:222222
					},{
            src: 'res/1.jpg',
            txt:222222
					},
					{
						src: 'res/2.jpg',
            txt:333333

					},
					{
						src: 'res/login.png',
            txt:4444
					},
          {
						src: 'res/5.jpg',
            txt:333333

					},
          {
						src: 'res/6.jpg',
            txt:333333

					},{
						src: 'res/7.jpg',
            txt:333333

					},{
						src: 'res/8.jpg',
            txt:333333
					},
          {
						src: 'res/100.jpg',
            txt:333333
					},
				],
      current:3,
		}
  },
  computed:{
  },
  methods: {
    gaibian(e){
      console.log(e,"传出来的值")
    },
    add(index,isAnimation){
      this.$refs.seiperDom.slideToNumber(index,isAnimation)
    },
    start(){
      console.log('开始了')
    },
    end(){
      console.log('结束了')
    }
  },
  components: {
    WBXswiper,
  },
  wbox: {
    onLoad() { },
    onShow() {
      // 页面显示/切入前台时触发
    },
    onHide() {
      // 页面隐藏时触发
    },
    onUnload() {
      // 页面退出时触发
    },
  },
  mounted() { },
};
export default pageOptions;
</script>

<style></style>

这里是组件内部,

<template>
  <wbx-view
    ref="objStyle"
    :style="wrapperStyle"
  >
    <wbx-view
      @touchstart~stop="onTouchStart"
      @touchmove~stop="onTouchMove"
      @touchend~stop="onTouchEnd"
      class="carousel-wrapper"
      :style="carouselStyle"
      @transitionend~stop="onTransitionEnd"
      ref="carouselWrapper"
    >
      <wbx-view :style="itemStyle">
        <slot name="swiperItem" :item="originalData[originalData.length - 1]"></slot>
      </wbx-view>
      <wbx-view v-for="(item, index) in originalData" :key="index" :style="itemStyle">
        <slot name="swiperItem" :item="item"></slot>
      </wbx-view>
      <wbx-view :style="itemStyle">
        <slot name="swiperItem" :item="originalData[0]"></slot>
      </wbx-view>
    </wbx-view>
    <wbx-view v-if="indicatorDots" :style="{ width: containerWidth + 'px' }" style="position: absolute; bottom: 10px; display: flex; flex-direction: row; justify-content: center;">
      <wbx-view
        v-for="(item, index) in originalData"
        :key="index"
        :style="{ backgroundColor: index == realIndex ? indicatorActiveColor : indicatorColor }"
        style="width: 20px; height: 20px; margin: 0 5px; cursor: pointer; border-radius: 10px;"
        @click~stop="setCurrentIndex(index+1)"
      ></wbx-view>
    </wbx-view>
  </wbx-view>
</template>

<script>
/*
originalData          数据
autoPlay              是否自动播放
interval              自动播放间隔时间
indicatorDots         是否显示指示点
indicatorColor        指示点颜色
indicatorActiveColor  当前选中的指示点颜色
current               当前的滑块是第几个 用法  :current.sync='current',外部数据跟组件内部是同步的
vertical              滑动方向是否为纵向
@currentChange        轮播图改变时会触发 currentChange 事件,返回当前滑块为第几个
@moveTouchStart       滑动开始触发的方法
@moveTouchEnd         滑动结束触发的方法
@slideToNumber(index,isAnimation) 调取这个方法可以直接跳转到某一个滑块  index为要跳转的第几个滑块, isAnimation为是否需要动画
*/
export default {
  props: {
    originalData: {
      type: Array,
      required: true
    },
    autoPlay: {
      type: Boolean,
      default: false
    },
    interval: {
      type: Number,
      default: 3000
    },
    indicatorDots: {
      type: Boolean,
      default: false
    },
    indicatorColor: {
      type: String,
      default: '#c0c0c0'
    },
    indicatorActiveColor: {
      type: String,
      default: '#fff'
    },
    current: {
      type: String,
      default: ''
    },
    vertical: {
      type: Boolean,
      default: false
    },
    modelValue: {
      type: Number,
      required: true,
    },
  },
  data() {
    return {
      currentIndex: 1,
      startIndex:'',
      timer: null,
      startX: 0,
      startY: 0,
      offset: 0,
      isTransitioning: false,
      containerWidth: 0,
      containerHeight: 0,
      userCurrent:false,
      userCurrentStare:false,
    };
  },
  watch: {
    current: {
        handler(newVal) {
          this.userCurrent=true
          this.setCurrentIndexDom(newVal);
        },
        immediate: true
    },
  },
  computed: {
    wrapperStyle() {
      return {
        position: "relative",
        width: `${this.wrapperWidth}px`,
        height: `${this.wrapperHeight}px`,
      };
    },
    carouselStyle() {
      const baseTranslateValue = -this.currentIndex * (this.vertical ? this.containerHeight : this.containerWidth);
      const translateValue = baseTranslateValue + this.offset;
      return {
        display: 'flex',
        flexDirection: this.vertical ? 'column' : 'row',
        transform: this.vertical ? `translateY(${translateValue}px)` : `translateX(${translateValue}px)`,
        transition: this.isTransitioning ? 'transform 0.3s ease-out' : 'none',
         width: !this.vertical ? `${this.wrapperWidth}px` : `${this.containerWidth}px`,
        height: this.vertical ? `${this.wrapperHeight}px` : `${this.containerWidth}px`
      };
    },
    wrapperWidth() {
      return this.containerWidth * (this.originalData.length + 2);
    },
    wrapperHeight() {
      return this.containerHeight * (this.originalData.length + 2);
    },
    itemStyle() {
      return {
        width: !this.vertical ? `${this.containerWidth}px` : `${this.containerWidth}px`,
        height: this.vertical ? `${this.containerHeight}px` : `${this.containerWidth}px`,
        flexShrink: 0
      };
    },
    realIndex() { 
      return (this.currentIndex - 1 + this.originalData.length) % this.originalData.length;
    }
  },
  mounted() {
    this.updateDimensions();
    this.$nextTick(() => {
      if (this.autoPlay) {
        this.startAutoPlay();
      }
    });
  },
  beforeDestroy() {
    this.stopAutoPlay();
  },
  methods: {
    updateDimensions() {
      if (this.$refs.objStyle) {
        const objStyle =  this.$refs.objStyle.styleObject
        this.containerWidth = parseFloat(objStyle.width);
        this.containerHeight = parseFloat(objStyle.height);
      }
    },
    startAutoPlay() {
      this.timer = setInterval(() => {
        this.next();
      }, this.interval);
    },
    stopAutoPlay() {
      if (this.timer) {
        clearInterval(this.timer);
        this.timer = null;
      }
    },
    next() {
      this.offset = 0;
      this.isTransitioning = true;
      this.currentIndex=this.currentIndex + 1;
      this.changeNumFn()
    },
    prev() {
      this.offset = 0;
      this.isTransitioning = true;
      this.currentIndex=this.currentIndex-1;
      this.changeNumFn()
    },
    changeNumFn(){
        let  num ='' 
        if(this.currentIndex>this.originalData.length){
          num=1
        }else if(this.currentIndex<1){
          num=this.originalData.length
        }else{
          num=this.currentIndex
        }
      this.$emit('update:current',num)
      this.$emit('currentChange', { current: num });
    },
    slideToNumber(index,isAnimation){
      if(index>0 && index<this.originalData.length){
        this.startIndex=index
      }else{
        return
      }
      this.stopAutoPlay();
      this.isTransitioning = isAnimation;
      this.currentIndex = index;
      this.changeNumFn()
      if (this.autoPlay) {
        this.startAutoPlay();
      }
    },
    setCurrentIndexDom(index){
      if(index==1||index==this.originalData.length||this.startIndex==index){
        return
      }
      if(this.current!==''){
        if(this.userCurrentStare==false){
          this.isTransitioning=false
          this.userCurrentStare=true
        }else{
          this.isTransitioning=true
        }
      }else{
        if(index==''){
            this.isTransitioning = false;
          }else{
            this.isTransitioning = true;
        }
      }
      this.currentIndex = index==''?1:index; 
    },
    setCurrentIndex(index) {
      this.stopAutoPlay();
      this.currentIndex = index==''?1:index; 
      if (this.autoPlay) {
        this.startAutoPlay();
      }
      this.changeNumFn()
    },
    onTouchStart(e) {
      this.startX = e.touches[0].clientX;
      this.startY = e.touches[0].clientY;
      this.offset = 0;
      this.stopAutoPlay();
      this.$emit('moveTouchStart',)
    },
    onTouchMove(e) {
      const moveX = e.touches[0].clientX;
      const moveY = e.touches[0].clientY;
      if(this.vertical){
        if(moveY - this.startY>=this.containerHeight){
          this.offset=this.containerHeight
        }else if(moveY - this.startY<= -this.containerHeight){
          this.offset=-this.containerHeight
        }else{
          this.offset= moveY - this.startY;
        }
      }else{
        if(moveX - this.startX>=this.containerWidth){
          this.offset=this.containerWidth
        }else if(moveX - this.startX<= -this.containerWidth){
          this.offset=-this.containerWidth
        }else{
          this.offset= moveX - this.startX;
        }
      }
    },
    onTouchEnd() {
      this.isTransitioning = true;
      this.$emit('moveTouchEnd')
      if (Math.abs(this.offset) > (this.vertical ? this.containerHeight : this.containerWidth) /6) {
        if (this.offset > 0) {
          this.prev();
        } else {
          this.next(111);
        }
      } else {
        this.offset = 0;
      }
      if (this.autoPlay) {
        this.startAutoPlay();
      }
    },
    onTransitionEnd() {
      this.isTransitioning = false;
      this.offset = 0;
      if (this.currentIndex === this.originalData.length + 1) {
        this.currentIndex = 1;
      }
      if (this.currentIndex === 0) {
        this.currentIndex = this.originalData.length;
      }
    }
  }
};
</script>

<style>
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值