前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue 自定义轮播

Vue 自定义轮播

作者头像
我不是费圆
发布2022-11-02 18:06:58
3540
发布2022-11-02 18:06:58
举报
文章被收录于专栏:鲸鱼动画鲸鱼动画

先看效果图:

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

配置信息如下:

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

源码如下:

代码语言: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%3A%2F%2Fimagepphcloud.thepaper.cn%2Fpph%2Fimage%2F206%2F104%2F959.jpg&refer=http%3A%2F%2Fimagepphcloud.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%3A%2F%2Fwww.dazijia.com%2FUploads%2Fjingdian%2F20210323%2Fy605991b3e31d3.jpg&refer=http%3A%2F%2Fwww.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%3A%2F%2Fphoto.tuchong.com%2F1658968%2Ff%2F149475915.jpg&refer=http%3A%2F%2Fphoto.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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-10-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 配置信息如下:
  • 源码如下:
  • 设计思路如下:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档