前些日子老板大人又安排了新的任務(wù)——banner的開(kāi)發(fā),拿到設(shè)計(jì)妹子給的設(shè)計(jì)圖之后,我的第一感覺(jué)就是——呵!看起來(lái)不難嘛!不就是用touchStart,touchmove,touchend組合+一些transition效果+一些位置計(jì)算就能實(shí)現(xiàn)了嗎???看我兩天內(nèi)不用輪子直接手寫(xiě)一個(gè)實(shí)現(xiàn)它!
。
。
。
一天半后
。
。
。
在嘗試了wx.createAnimation()中的translateX/left+原生的css3的transition之后,我拿起了鏡子,摸了摸被自己打腫的臉,心里滿(mǎn)是委屈:這特喵的效果怎么都不按照預(yù)想的來(lái)??!是我的寫(xiě)法不對(duì)還是因?yàn)閙pvue各種坑使???我開(kāi)始深深滴懷疑自己。。。在基本確定此路不通之后(后來(lái)了解到其實(shí)應(yīng)該是mpvue數(shù)據(jù)更新機(jī)制的問(wèn)題,每次修改一個(gè)data()里面的值,都會(huì)刷新其他的值,不信你可以在mpvue中去試試用scroll-view組件的scroll-top屬性實(shí)現(xiàn)返回頂部試試。。。),我打開(kāi)了技術(shù)群,拋出了問(wèn)題,然后有人指出其實(shí)用小程序的swiper應(yīng)該也可以實(shí)現(xiàn)的,這個(gè)想法我之前在某一瞬間曾經(jīng)有過(guò)——swiper設(shè)置好基礎(chǔ)參數(shù),然后額外加一些樣式,應(yīng)該可以實(shí)現(xiàn)。這位仁兄的思路和我不謀而合(咳咳咳,我先不要臉,你們隨意),我也重拾信心,下面呢,就是具體的實(shí)現(xiàn)方法以及效果了:
動(dòng)圖我并不會(huì)做,就放一張截圖吧,想看具體的效果的小伙伴們可以去我 github的項(xiàng)目:mpvue-banner 上下載并且跑起來(lái)看一下(我是真的不知道怎么在MacBook上制作gif,如果有哪位小伙伴知道,可以在評(píng)論里告知,感謝感謝!),如果這個(gè)banner不是你想要的效果,您可以選擇不再往下看,或者可以看看實(shí)現(xiàn)的思路~下面先看下圖片吧

banner就在上圖中紅色框內(nèi),可以看到此款banner并沒(méi)有像大多數(shù)banner一樣占據(jù)整個(gè)屏幕的寬度,而是前后的banner圖都露出了一部分,而且展示的banner圖比前后的banner圖片大小上還放大了一定的倍數(shù),這樣看下來(lái)是不是覺(jué)得整體設(shè)計(jì)上要比默認(rèn)的banner效果好了不少呢?如果還有興趣的話(huà),請(qǐng)繼續(xù)往下看具體的實(shí)現(xiàn)思路以及代碼
mpvue的該組件也是基于小程序原生的swiper組件實(shí)現(xiàn)的,具體的屬性我就不再挨個(gè)介紹了,畢竟官方文檔里寫(xiě)的很清楚了~這里就主要說(shuō)下我們要實(shí)現(xiàn)上圖中的banner要依賴(lài)的最重要的兩個(gè)屬性previous-margin和next-margin,前者主要作用是「露出前一項(xiàng)的一小部分」,后者主要作用是「露出后一項(xiàng)的一小部分」,好了,我們先把mpvue-swiper組件介紹中的代碼copy 過(guò)來(lái):
<template>
<div class="page">
<view class="page__hd">
<view class="page__title">Swiper</view>
<view class="page__desc">滑塊視圖容器,這里采用小程序原生 swiper 組件實(shí)現(xiàn)。</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 + '張輪播圖發(fā)生了滑動(dòng)');
},
animationfinish(e) {
console.log('第' + e.mp.detail.current + '張輪播圖滑動(dòng)結(jié)束');
}
}
}
</script>
<style>
.slide-image {
width: 100%;
height: 100%;
}
</style>
復(fù)制代碼
粘完這些代碼,你能實(shí)現(xiàn)一個(gè)很常規(guī)的banner了,然后我們加上剛剛我們提到的那兩個(gè)屬性:
<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>
復(fù)制代碼
這時(shí)候你就實(shí)現(xiàn)了一個(gè)能將前一項(xiàng)和后一項(xiàng)各露出60rpx的banner了,只不過(guò)此時(shí)各項(xiàng)的圖片大小都是相同的,那怎么實(shí)現(xiàn)主項(xiàng)的圖片大小的放大呢,當(dāng)然是使用css的transform給圖片標(biāo)簽加各放大的樣式,且往下看代碼:
<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: 動(dòng)態(tài)值,需要根據(jù)設(shè)計(jì)圖以及banner圖片的個(gè)數(shù)以及位置進(jìn)行計(jì)算得出,
padding: 動(dòng)態(tài)值,需要根據(jù)設(shè)計(jì)圖以及banner圖片的個(gè)數(shù)以及位置進(jìn)行計(jì)算得出
}">
<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>
復(fù)制代碼
其中幾個(gè)出現(xiàn)的參數(shù):
currentIndex:即當(dāng)前展現(xiàn)的banner項(xiàng)的索引
bannerIndex:即banner項(xiàng)在整個(gè)圖片列表中的索引
scaleX以及scaleY:即你希望的主項(xiàng)的放大的倍數(shù),此項(xiàng)的值可能需要我們根據(jù)屏幕寬度以及設(shè)計(jì)稿的展示來(lái)進(jìn)行計(jì)算
這幾個(gè)樣式就是:將當(dāng)前展示的圖片放大一定的倍數(shù)
到了這里,我們需要的結(jié)構(gòu)以及style上的代碼基本上都有了,下面主要是script里對(duì)一些關(guān)鍵的參數(shù)進(jìn)行控制,這里有個(gè)比較重要的函數(shù)@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以及動(dòng)畫(huà)執(zhí)行索引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>
復(fù)制代碼
至此呢,主圖中的banner的主要效果基本已經(jīng)實(shí)現(xiàn)了,看下來(lái)其實(shí)并不是很難,主要是一些細(xì)節(jié)需要特別注意:
它們的值并不是隨便寫(xiě)的,需要你根據(jù)設(shè)計(jì)圖去進(jìn)行細(xì)微的計(jì)算
其中我沒(méi)有寫(xiě)出具體值的兩項(xiàng)屬性:justifyContent與padding,他們的具體值同樣需要你去進(jìn)行計(jì)算,此時(shí)的計(jì)算不止會(huì)涉及到設(shè)計(jì)稿,他們的值還會(huì)根據(jù)當(dāng)前展示出來(lái)的三張圖片在整個(gè)imgList(至少三項(xiàng))中的順序的不同而不同,在我的實(shí)現(xiàn)中我使用了超長(zhǎng)的三目運(yùn)算符來(lái)保證每個(gè)圖片的具體的屬性值。。。