Vue 自定义轮播

2022-11-02 18:06:58 浏览数 (3)

先看效果图:

 开发可视化大屏的时候想在网上随便找一个,翻了翻都不太满意就手撸了一个,

配置信息如下:

有些属于“预留”功能,目前没有达到理想效果,后续我会在这篇博客里继续完善,

源码如下:

代码语言:javascript复制
<template>
  <div>
    <div class="swiper-title">自定义轮播图</div>
    <div class="swiper-box">
      <!-- 轮播区域 -->
      <div :class="[config.column ? 'column-row' : '']" class="swiper">
        <div v-for="(item, index) in list" :key="index" :class="[nowInd === index ? 'focus' : '']" class="swiper-item"
          :style="{
            backgroundImage: `url(${item.url})`,
            transition: `all ${nowFlag ? (config.changeTime < config.waitTime ? config.changeTime   's' : '0.5s') : '0s'}`,
            transform: config.column ? `translateX(-${100 * nowInd}%)` : `translateY(-${100 * nowInd}%)`,
          }">
          <p class="title">文字和图片没有什么关联</p>
          <p class="info">图片是河南开封的美景</p>
          <p class="name">{{ item.name }}</p>
        </div>
      </div>
      <!-- 指示点 -->
      <div v-if="config.spot" class="spot-flex">
        <div @click="spotActive(ind)" v-for="ind in list.length - 1" :key="ind"
          :class="[nowInd === ind ? 'focus' : '', config.spotStyle ? `spot${config.spotStyle}` : 'spot1']" class="spot">
        </div>
      </div>
      <!-- 左右切换 -->
      <img v-if="config.arrow" @click="spotActive('-')"
        src="https://img-blog.csdnimg.cn/ae2239969edd48cc803da677dd791865.png" alt="" class="icon left">
      <img v-if="config.arrow" @click="spotActive(' ')"
        src="https://img-blog.csdnimg.cn/46d9862a4c3e42819a79ebd2b84d0d73.png" alt="" class="icon right">
      <!-- 控制台 -->
      <!-- <div class="operate">
        <div class="row">
          <span>排列方式:</span>
          <input type="radio">
          <input type="radio">
          <input v-model="config.column" type="text">
        </div>
      </div> -->
    </div>
  </div>
</template>
<script>
export default {
  name: "Swiper",
  data() {
    return {
      config: {
        column: true,   // true: 横向排列  false: 纵向排列
        changeStyle: 2, // 切换风格 (可选1、2)
        changeTime: 1,  // 转换时长(秒)  转换时长必须小于等待时长,默认为500毫秒
        waitTime: 2,    // 等待时长(秒)  等待时长最短为1s
        spot: true,     // 指示点 true: 显示  false: 隐藏
        spotStyle: 1,   // 指示点风格 (可选1、2、3)
        arrow: false,   // 左右切换按钮 true: 显示  false: 隐藏
      },
      nowInd: 0,        // 轮播图当前下标
      nowFlag: true,    // 过渡控制器
      myInt: '',        // 轮播图计时器
      list: [
        { name: '巍峨壮丽连绵不绝的山脉', url: 'https://gimg2.baidu.com/image_search/src=http://imagepphcloud.thepaper.cn/pph/image/206/104/959.jpg&refer=http://imagepphcloud.thepaper.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1663147037&t=19521f70b52350b3d1ad05c57d71dd0e' },
        { name: '傍晚的天空和海面的霞光', url: 'https://gimg2.baidu.com/image_search/src=http://www.dazijia.com/Uploads/jingdian/20210323/y605991b3e31d3.jpg&refer=http://www.dazijia.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1663147229&t=f32746ac1f21b8e1d243747e9353fa16https://img0.baidu.com/it/u=2725915437,1236608227&fm=253&fmt=auto&app=138&f=JPEG?w=750&h=500' },
        { name: '峻峭的雪山景色', url: 'https://gimg2.baidu.com/image_search/src=http://photo.tuchong.com/1658968/f/149475915.jpg&refer=http://photo.tuchong.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1663147301&t=1be195b9d22a1307a66fb8e19697fb54' }
      ]
    }
  },
  mounted() {
    this.list.length > 0 ? this.list.push(this.list[0]) : '';
    this.autoInt()
  },
  methods: {
    // 轮播图计时器
    autoInt() {
      clearInterval(this.myInt)
      this.myInt = setInterval(() => {
        this.nowInd  
        if (this.nowInd > this.list.length - 1) {
          this.nowFlag = false;
          this.nowInd = 0
          setTimeout(() => {
            this.nowFlag = true;
            this.nowInd  
          }, 10)
        }
      }, this.config.waitTime * 1000 < 1000 ? 1000 : this.config.waitTime * 1000)
    },
    // 指示点/左右按钮点击
    spotActive(ind) {
      if (ind === ' ') {
        this.nowInd < this.list.length - 2 ? this.nowInd   : this.nowInd = 0
      } else if (ind === '-') {
        this.nowInd > 0 ? this.nowInd-- : this.nowInd = this.list.length - 2
      } else {
        this.nowInd = ind;
      }
      this.autoInt()
    },
  }
}
</script>
<style lang="scss" scoped>
.swiper-title {
  width: 600px;
  text-align: center;
  line-height: 40px;
  font-size: 22px;
  font-family: 仿宋;
  font-weight: 500;
  color: #f7c40b;
}

.column-row {
  white-space: nowrap;

  .swiper-item {
    display: inline-block;
  }
}

.swiper-box {
  position: relative;
  width: 600px;
  height: 360px;

  .swiper {
    width: 100%;
    height: 100%;
    overflow: hidden;

    .swiper-item {
      width: 100%;
      height: 100%;
      background: no-repeat center;
      background-size: cover;
      overflow: hidden;

      .title,
      .info,
      .name {
        transform: translateX(-100%)
      }
    }

    .focus {

      .title,
      .info,
      .name {
        transform: translateX(20px);
      }

      .title {
        transition: all .6s .3s;
      }

      .info {
        transition: all .6s .5s;
      }

      .name {
        transition: all .6s .7s;
      }
    }
  }

  .icon {
    position: absolute;
    top: 0;
    bottom: 0;
    margin: auto;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    cursor: pointer;
  }

  .left {
    left: 0;
  }

  .right {
    right: 0;
  }

  .spot-flex {
    position: absolute;
    left: 0;
    right: 0;
    bottom: -20px;
    margin: auto;
    display: flex;
    justify-content: center;
    align-items: center;

    .spot1 {
      width: 30px;
      height: 8px;
      margin: 0 10px;
      border-radius: 4px;
      background-color: pink;
      transition: all .6s;
      cursor: pointer;
    }

    .spot2 {
      width: 6px;
      height: 6px;
      margin: 0 10px;
      border: 2px solid #acd6f3;
      transform: rotate(45deg);
      transition: all .6s;
      cursor: pointer;
    }

    .spot3 {
      width: 6px;
      height: 6px;
      margin: 0 10px;
      border-radius: 3px;
      box-shadow: 0px 0px 6px 3px #acd6f3;
      transition: all .6s;
      cursor: pointer;
    }

    .focus {
      background-color: skyblue;
    }
  }
}

.operate {
  margin-left: 40px;

  .row {
    display: flex;
    align-items: center;
    font-size: 14px;
  }
}
</style>

组件开发的比较潦草,后续会进行迭代和完善,继续在这篇文章里进行更新。

设计思路如下:

划分标题、轮播区、指示点三块,在轮播区使用 display: inline-block; ​使子元素横向排列,

此时​限制父元素的宽度,子元素会自动换行,使用 white-space: nowrap; 则强制不换行。

使用动态样式的写法,判断column 的属性值,以此来实现横向或纵向排列。

使用计时器控制变量 nowInd 变化,当nowInd 发生改变会影响轮播图上的判断条件,进而控制轮播运动

根据config.column 的值,判断是进行左右移动 还是上下移动,用transition 来动态控制过渡效果的有无。

文字的滑动效果来自于 css 动画,代码如下:

代码语言:javascript复制
.focus {
  .title,.info,.name {
    transform: translateX(20px);
  }

  .title {
    transition: all .6s .3s;
  }

  .info {
    transition: all .6s .5s;
  }

  .name {
    transition: all .6s .7s;
  }
}

通过nowInd 是否等于当前子元素的下标,以此来断定是否聚焦了当前的子元素,当子元素满足条件拥有.focus 时,子元素向右移动,给不同的延迟时间,以此实现波浪化。

三种指示点共用同一套动画,样式也进行和封装和复用,需要别的款式可以仿照我现在的代码进行更改。

这里为了高度复用性,使用的并不是img 轮播,而是div 区域轮播,以背景图的形式体现

可以根据不同的需求更改或隐藏背景图,在div 里进行自定义排版。

暂时就讲到这里了,后续会在这篇文章的底部继续更新该组件,感兴趣的话可以收藏一下,see you

1 人点赞