来吧,一块儿给小程序原生的swiper化个妆,让她变成更漂亮点的banner吧(基于mpvue)

    前些日子老板大人又安排了新的任务——banner的开发,拿到设计妹子给的设计图以后,个人第一感受就是——呵!看起来不难嘛!不就是用touchStart,touchmove,touchend组合+一些transition效果+一些位置计算就能实现了吗???看我两天内不用轮子直接手写一个实现它!css

        。
        。
        。
    一天半后
        。
        。
        。
    在尝试了wx.createAnimation()中的translateX/left+原生的css3的transition以后,我拿起了镜子,摸了摸被本身打肿的脸,内心尽是委屈:这特喵的效果怎么都不按照预想的来啊!是个人写法不对仍是由于mpvue各类坑使???我开始深深滴怀疑本身。。。在基本肯定此路不通以后(后来了解到其实应该是mpvue数据更新机制的问题,每次修改一个data()里面的值,都会刷新其余的值,不信你能够在mpvue中去试试用scroll-view组件的scroll-top属性实现返回顶部试试。。。),我打开了技术群,抛出了问题,而后有人指出其实用小程序的swiper应该也能够实现的,这个想法我以前在某一瞬间曾经有过——swiper设置好基础参数,而后额外加一些样式,应该能够实现。这位仁兄的思路和我不谋而合(咳咳咳,我先不要脸,大家随意),我也重拾信心,下面呢,就是具体的实现方法以及效果了:html

1.先看下效果吧

    动图已放(LICEcap制做)!感谢评论里的@wangx老哥!想看具体的效果的小伙伴们能够去我github的项目:mpvue-banner上下载而且跑起来看一下,若是这个banner不是你想要的效果,您能够选择再也不往下看,或者能够看看实现的思路~具体效果以下:vue

banner就在上图中红色框内,能够看到此款banner并无像大多数banner同样占据整个屏幕的宽度,而是先后的banner图都露出了一部分,并且展现的banner图比先后的banner图片大小上还放大了必定的倍数,这样看下来是否是以为总体设计上要比默认的banner效果好了很多呢?若是还有兴趣的话,请继续往下看具体的实现思路以及代码

2.看完了效果,咱们再来看下mpvueswiper组件吧

    mpvue的该组件也是基于小程序原生的swiper组件实现的,具体的属性我就再也不挨个介绍了,毕竟官方文档里写的很清楚了~这里就主要说下咱们要实现上图中的banner要依赖的最重要的两个属性previous-marginnext-margin,前者主要做用是「露出前一项的一小部分」,后者主要做用是「露出后一项的一小部分」,好了,咱们先把mpvue-swiper组件介绍中的代码copy 过来:css3

<template>
  <div class="page">
    <view class="page__hd">
      <view class="page__title">Swiper</view>
      <view class="page__desc">滑块视图容器,这里采用小程序原生 swiper 组件实现。</view>
    </view>
    <div class="page__bd page__bd_spacing">
      <swiper :indicator-dots="indicatorDots" 
        :autoplay="autoplay" 
        :interval="interval" 
        :duration="duration" 
        :circular="circular" 
        @change="swiperChange" 
        @animationfinish="animationfinish">
        <div v-for="item in imgUrls" :key="index">
          <swiper-item>
            <image :src="item" class="slide-image" />
          </swiper-item>
        </div>
      </swiper>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      indicatorDots: true,
      autoplay: true,
      interval: 5000,
      duration: 900,
      circular: true,
      imgUrls: [
        'http://img02.tooopen.com/images/20150928/tooopen_sy_143912755726.jpg',
        'http://img06.tooopen.com/images/20160818/tooopen_sy_175866434296.jpg',
        'http://img06.tooopen.com/images/20160818/tooopen_sy_175833047715.jpg'
      ]
    }
  },
  methods: {
    swiperChange(e) {
      console.log('第' + e.mp.detail.current + '张轮播图发生了滑动');
    },
    animationfinish(e) {
      console.log('第' + e.mp.detail.current + '张轮播图滑动结束');
    }
  }
}
</script>
<style>
.slide-image {
  width: 100%;
  height: 100%;
}
</style>
复制代码

粘完这些代码,你能实现一个很常规的banner了,而后咱们加上刚刚咱们提到的那两个属性:git

<swiper :indicator-dots="indicatorDots" 
        :autoplay="autoplay" 
        :interval="interval" 
        :duration="duration" 
        :circular="circular" 
        :previous-margin="'60rpx'"
        :next-margin="'60rpx'"
        @change="swiperChange" 
        @animationfinish="animationfinish">
        <div v-for="item in imgUrls" :key="index">
          <swiper-item>
            <div class="img-wrapper">
                <image :src="item" class="slide-image" />
            </div>
          </swiper-item>
        </div>
    </swiper>
复制代码

这时候你就实现了一个能将前一项和后一项各露出60rpx的banner了,只不过此时各项的图片大小都是相同的,那怎么实现主项的图片大小的放大呢,固然是使用css的transform给图片标签加各放大的样式,且往下看代码:github

<swiper :indicator-dots="indicatorDots" 
        :autoplay="autoplay" 
        :interval="interval" 
        :duration="duration" 
        :circular="circular" 
        :previous-margin="'60rpx'"
        :next-margin="'60rpx'"
        @change="swiperChange" 
        @animationfinish="animationfinish">
        <div v-for="item in imgUrls" :key="index">
          <swiper-item>
            <div class="img-wrapper"
                :style="{ boxSizing: 'border-box', width: '100%', height: '100%', display: 'flex', justifyContent: 动态值,须要根据设计图以及banner图片的个数以及位置进行计算得出, padding: 动态值,须要根据设计图以及banner图片的个数以及位置进行计算得出 }">
                <image :src="item" 
                    class="slide-image" 
                    :style="{ transform: currentIndex===bannerIndex?'scale(' + scaleX + ',' + scaleY + ')':'scale(1,1)', transitionDuration: '.3s', transitionTimingFunction: 'ease' }"/>
            </div>
          </swiper-item>
        </div>
    </swiper>
复制代码

其中几个出现的参数:
currentIndex:即当前展示的banner项的索引
bannerIndex:即banner项在整个图片列表中的索引
scaleX以及scaleY:即你但愿的主项的放大的倍数,此项的值可能须要咱们根据屏幕宽度以及设计稿的展现来进行计算
这几个样式就是:将当前展现的图片放大必定的倍数
到了这里,咱们须要的结构以及style上的代码基本上都有了,下面主要是script里对一些关键的参数进行控制,这里有个比较重要的函数@changenpm

<script>
data () {
    return {
        autoplay: false,
        interval: 3000,
        duration: 300,
        circular: true,
        currentIndex: 0,
        scaleX: (634 / 550).toFixed(4),
        scaleY: (378 / 328).toFixed(4)
    }
},
methods: {
    // 控制currentIndex以及动画执行索引descIndex的值
    swiperChange (e) {
        const that = this
        this.currentIndex = e.mp.detail.current
        this.scaleX = (634 / 550).toFixed(4)
        this.scaleY = (378 / 328).toFixed(4)
    }
}
</script>
复制代码

3.注意点

至此呢,主图中的banner的主要效果基本已经实现了,看下来其实并非很难,主要是一些细节须要特别注意:小程序

3.1:previous-margin和next-margin的值

它们的值并非随便写的,须要你根据设计图去进行细微的计算api

3.2:swiper-item内,image标签外的class名为img-wrapper的div容器的样式

其中我没有写出具体值的两项属性:justifyContent与padding,他们的具体值一样须要你去进行计算,此时的计算不止会涉及到设计稿,他们的值还会根据当前展现出来的三张图片在整个imgList(至少三项)中的顺序的不一样而不一样,在个人实现中我使用了超长的三目运算符来保证每一个图片的具体的属性值。。。bash

3.小结

    项目已经上传至github:mpvue-banner,欢迎fork或者讨论,因为可定制性太强,就不写成npm包了,你们须要的话本身去研究吧!     因为mpvue的一些的坑的存在,致使咱们像本身实现一些轮子确实很困难,在这种状况下,咱们就要学会如何利用现成的轮子去改造,进而去实现咱们本身所需的轮子。造不出轮子没关系,但咱们要保持一颗研(mo)究(fang)进(gai)取(zao)的❤️!     这个介绍到这而就打住了,其实这期也没什么东西,我想对于不少人来讲只要肯花时间和精力,实现这样的效果就是小菜一碟!     “咱们不造轮子,咱们只作轮子的改造者与搬运工”

相关文章
相关标签/搜索