前几天,老板安排了一个新任务,开发——banner。拿到设计女孩的设计图后,第一感觉是——!看起来不难!不使用touchStart、touchmove、touchend来组合一些过渡效果,有没有可能实现一些位置计算?看,过两天不用轮子直接手写就行了!。
一天半后。。
在wx.createAnimation()中尝试了translateX/left的原生css3的过渡后,我拿起镜子摸了摸肿了的脸。我心里满是委屈:这种特殊的喵叫效果为什么没有像预期的那样去!是我写错了还是因为mpvue的各种花招?我开始深深怀疑自己。在基本确定这条路不通之后(后来才知道,其实应该是mpvue的数据更新机制的问题。每次修改数据()中的值时,都会刷新其他值。如果你不相信我,你可以试着用mpvue中滚动视图组件的滚动顶部属性返回顶部。),我打开技术组,抛出了一个问题,然后有人指出用小程序的swiper应该也能实现这个想法。之前有一次让——swiper在某个时刻设置了基本参数,然后增加了一些样式,应该可以实现。亲爱的朋友的想法和我不谋而合(咳咳,我先不要脸了,你自由了),我也重拾信心。以下是具体的实现方法和效果:
我不会做动画,就放一张截图,想看具体效果的朋友可以从我的github项目:mpvue-banner下载下来跑去看一看(我真的不知道MacBook上怎么做gif,如果有朋友知道的话,可以在评论里告诉我们,谢谢!),如果这个横幅不是你想要的效果,可以选择不往下看,也可以看看实现的想法~先看图。
横幅在上图中的红色方框中。可以看到,这个横幅并没有像大多数横幅那样占据整个屏幕的宽度,只是前后横幅图像部分曝光,显示的横幅图像相比前后横幅图像放大了一定倍数。你觉得整体设计比默认的横幅效果好很多吗?如果还感兴趣,请继续往下看具体的实现思路和代码。
mpvue的这个组件也是基于小程序的原生swiper组件实现的,具体属性我就不一一介绍了。毕竟公文里写的很清楚~这里主要说一下上图中我们要靠实现banner最重要的两个属性,上一页边空白和下一页边空白。前者主要用于“暴露前一项的一小部分”,后者主要用于“暴露后一项的一小部分”。好了,让我们先复制mpvue-swiper组件介绍中的代码:
模板类=' page '视图类=' page _ _ HD '视图类=' page _ _ title ' swiper/视图类=' page _ _ desc '滑块视图容器,由applet原生Swiper组件实现。/view/view div class=' page _ _ BD page _ _ BD _ spacing ' swiper : indicator-dots=' indicator dots ' : autoplay=' autoplay ' : interval=' interval ' : duration=' duration ' : circular=' circular ' @ change=' swi penge ' @ animation finish=' animation finish ' div-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了,然后我们加上刚刚我们提到的那两个属性:
<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给图片标签加各放大的样式,且往下看代码:
<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里对一些关键的参数进行控制,这里有个比较重要的函数@change
<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>复制代码
至此呢,主图中的banner的主要效果基本已经实现了,看下来其实并不是很难,主要是一些细节需要特别注意:
它们的值并不是随便写的,需要你根据设计图去进行细微的计算
其中我没有写出具体值的两项属性:justifyContent与padding,他们的具体值同样需要你去进行计算,此时的计算不止会涉及到设计稿,他们的值还会根据当前展示出来的三张图片在整个imgList(至少三项)中的顺序的不同而不同,在我的实现中我使用了超长的三目运算符来保证每个图片的具体的属性值。。。