网站首页 » 前端开发 » 前端工具 » 小程序做一个图片切换效果
上一篇:
下一篇:

小程序做一个图片切换效果

前言

下面来做一个图片切换效果,这个效果是从附近的微群小程序中看到的,觉得效果还不错,用户体验比微信小程序中的 swiper 组件的默认效果会好很多,没有那么中规中矩。不过在附近的微群小程序中的这个效果也不是很完美,手动操作切换图片时有明显的不流畅。

小程序图片切换之旅

为此,我也尝试做了一个类似的切换效果,不过做完之后效果比附近的微群小程序中的切换效果更好,理由如下:

1、图片切换如丝般顺滑

2、可指定默认显示第几个

3、可设置自动播放。

我把这个效果封装成了一个小程序组件,你只需要往里面传些参数就好。

效果:

小程序做一个图片切换效果

下面就是代码分享时间:

banner/banner.js
Component({
  properties: {
    listData: {
      type: Array,
      value: []
    },
    indicatorDots: { // 是否显示面板指示点
      type: Boolean,
      value: true
    },
    autoPlay: { // 是否自动播放
      type: Boolean,
      value: false
    },
    interval: { // 切换时间间隔(自动播放时有效)
      type: Number,
      value: 300
    },
    duration: { // 切换动画时长
      type: Number,
      value: 1000
    },
    defaultIndex: { // 默认显示第一个
      type: Number,
      value: 0
    },
    indicatorColor: {
      type: String,
      value: "rgba(255,255,255,0.5)"
    },
    indicatorActiveColor: {
      type: String,
      value: "#fff"
    }
  },
  data: {
    baseUrl: http.getBaseUrl(),
    currentIndex: 0,
    realAutoPlay: false,
    isSetDefault: false // 标记首次初始化
  },
  methods: {
    imgLoaded: function(event) { // 每张图片加载完后都会触发这个函数(这个不是关键代码,去掉也不影响图上切换效果)
      const currentTarget = event.currentTarget;
      const index = currentTarget.dataset.index;
      let listData = this.data.listData;
      for (let i = 0, item; item = listData[i++];) {
        if (item.id === currentTarget.id) { // 找到这张加载完成的图片,并设置的状态为已加载
          item.isLoaded = true;
        }
      }
      // 如果图片都已经加载完
      // if (index === bannerList.length){
      this.setData({
        listData: listData
      });
      // }

    },
    changeBanner: function(event) {
      const data = this.data;
      this.setData({
        currentIndex: event.detail.current
      });
      // 通过自动切换来 hack 到指定默认页
      if (!data.isSetDefault && event.type === "change") {
        if (data.currentIndex === data.defaultIndex) {
          data.isSetDefault = true; // 设置完默认页
          if (data.autoPlay) { // 如果设置了自动播放,则切换到默认页后开始自动播放
            this.setData({
              realAutoPlay: true,
              realInterval: data.interval
            });
          } else { //否则只切换到默认页
            this.setData({
              realAutoPlay: false
            });
          }
        }
      }
    },
    goDetail: function(event) { // 这个不是切换效果的关键代码,只是为图片提供跳转而已,同样的,去掉也不会影响图片切换效果
      const dataSet = event.currentTarget.dataset;
      const linkAddress = dataSet.linkAddress;
      const linkType = dataSet.linkType;
      const pageId = dataSet.pageId;
      if (!linkAddress) {
        return;
      }
      if (linkType === 0) { // 小程序中页面之间的跳转
        wx.navigateTo({
          url: linkAddress
        })
      } else if (linkType === 1) { // 小程序之间跳转
        const appId = dataSet.appId;
        wx.navigateToMiniProgram({
          appId: appId,
          path: linkAddress
        })
      }
    },

  },
  ready: function() {
    const data = this.data;
    this.setData({
      realAutoPlay: !!!data.defaultIndex ? false : true, // 如果没设置默认页或者设置页为第一个则关闭自动切换
      listData: data.listData
    });
  },
});
banner.wxml
<view class="swiper-box">
  <swiper indicator-dots="{{indicatorDots}}" indicator-active-color="{{indicatorActiveColor}}" indicator-color="{{indicatorColor}}" autoplay="{{realAutoPlay}}" interval="{{realInterval}}" duration="{{duration}}" previous-margin="120rpx" next-margin="120rpx" bindchange="changeBanner"
    class='swiper-box-inner'>
    <block wx:for="{{listData}}" wx:key="index">
      <swiper-item class="swiper-item swiperItem" bindtap="goDetail" data-page-id="{{item.id}}" data-app-id="{{item.miniProgramId}}" data-link-type="{{item.linkType}}" data-link-address="{{item.linkAddress}}">
        <view class="slide-item-inner {{index === currentIndex?'slide-item-inner-center':'slide-item-inner-side'}}">
          <view class="title">{{item.isLoaded ? item.title:"图片拼命加载中..."}}</view>
          <image bindload="imgLoaded" data-index="{{index+1}}" class="slide-image {{item.isLoaded ? '':'waiting'}}" id="{{item.id}}" src="{{item.picUrl}}" />
        </view>
      </swiper-item>
    </block>
  </swiper>
</view>
banner.wxss
.swiper-box{
  padding-top: 50rpx;
  height: 87vh;
}
.swiper-box-inner{
  height: 85vh;
}
.swiper-item{
    perspective: 500px;
    overflow: inherit;
}
.slide-item-inner{
  transition: all 0.5s ease-in-out 0s;
  display: flex;
  flex-direction: column;
  height: 79vh;
  justify-content: center;
}
.slide-item-inner-center{
  opacity: 1; 
  transform: translate3d(0px, 0px, 0px);
}
.slide-item-inner-side{
  opacity: 0.5; 
  transform: translate3d(0px, 0px, -150px); 
}

.slide-item-inner .title{
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
  word-break:break-all;
  color: #fff;
  font-size: 46rpx;
}

.slide-image{
  margin: 28rpx auto 0;
  width: 65vw;
  /* 490/785 为图片宽高比例*/
  height: calc(65vw*785/490); 
  border-radius: 10rpx;
  box-shadow: 0 0 12px rgba(0, 0, 0, 0.3);
  transition: all 0.5s ease-in-out 0s;
}

.waiting{
  width: 100rpx;
  height: 100rpx;
  animation: rotater 0.5s infinite alternate;
}
@keyframes rotater{
  0%{
   border-radius: 10rpx;
   /* transform: rotate(0deg) */
  }
  100%{
    border-radius: 50%;
    /* transform: rotate(360deg) */
  }
}
@-webkit-keyframes rotater{
  0%{
    border-radius: 10rpx;
  /* transform: rotate(0deg) */
  }

  100%{
    border-radius: 50%;
   /* transform: rotate(360deg) */
  }
}

用法很简单,先在要使用这个组件的所对应页面的 .json 文件中引入这个小程序组件:

index.json
{
    "navigationBarTextStyle": "white",
    "navigationBarTitleText": "云库网",
    "navigationBarBackgroundColor": "#4f76ec",
    "usingComponents": {
      "banner": "../../components/banner/banner"
    }
}

然后在页面的 .wxml 文件中通过标签来使用这个组件就可以了:

index.wxml
<banner wx:if="{{bannerLoaded}}" auto-play="true" interval="3000" indicator-color="rgba(255,255,255,0.5)" indicator-active-color="#fff" indicator-dots="true" list-data="{{bannerList}}" defaultIndex="{{defaultIndex}}"></banner>

为什么要用 wx:if=”{{bannerLoaded}}” ?意思就是默认不渲染这个组件,等什么什么时候才渲染这个组件呢?等数据都从服务端请求回来后,我们才把 bannerLoaded 设置为 true。这样就保证了在组件渲染之前,传到组件内的数据就已经准备好,如果不这么做的话,组件渲染时,服务端还没返回数据,这就没法玩了。

上面这个组件基本同步小程序中 swiper 组件的参数,所以你可以很容易的对其进行相关参数设置。

总结:

1、组件传参前不需要加 data-

2、properties 属性可以实现数据监听

  • 微信扫一扫,赏我

  • 支付宝扫一扫,赏我

声明

原创文章,不经本站同意,不得以任何形式转载,如有不便,请多多包涵!

本文永久链接:http://yunkus.com/mini-program-animation-banner/

发表评论

电子邮件地址不会被公开。 必填项已用*标注

评论 END