初始需要给item们放置好位置以及各种层级,然后在切换滑动的过程中对设置的位置、层级、透明度进行替换,加上小程序的wx.createAnimation()动画效果。
<view class="swiper-page" bindtouchmove="touchmove" bindtouchstart="touchstart" bindtouchend="touchend">
<view wx:for="{{imgArray}}" wx:key="index" class="swiper-container">
<view class="item-container" style="z-index:{{indexArray[index]}}">
<view class="item{{index}} item-common" animation="{{animation[index]}}" data-text="{{textArray[index]}}">
<image class="background" src="{{item.image}}" mode='aspectFit'></image>
<text class="item-text">{{item.text}}</text>
</view>
</view>
</view>
<view bindtap="tapLeft" style="position:absolute;top:0;left:20rpx">往左滑</view>
<view bindtap="tapRight" style="position:absolute;top:0;right:20rpx">往右滑</view>
</view>
<view class="swiper-page" bindtouchmove="touchmove" bindtouchstart="touchstart" bindtouchend="touchend">
<view wx:for="{{imgArray}}" wx:key="index" class="swiper-container">
<view class="item-container" style="z-index:{{indexArray[index]}}">
<view class="item{{index}} item-common" animation="{{animation[index]}}" data-text="{{textArray[index]}}">
<image class="background" src="{{item.image}}" mode='aspectFit'></image>
<text class="item-text">{{item.text}}</text>
</view>
</view>
</view>
<view bindtap="tapLeft" style="position:absolute;top:0;left:20rpx">往左滑</view>
<view bindtap="tapRight" style="position:absolute;top:0;right:20rpx">往右滑</view>
</view>
// 位置列表
let posArray = [ 280,120,420]
// 缩放列表
let scaArray = [1, .8, .8 ]
// 透明度列表
let opaArray = [1,.8, .8]
// 高度列表
let indArray = [ 1, 0.8, 0.8]
// 当前位置列表
let curPosArray = [ 280,120,420]
// 当前缩放列表
let curScaArray = []
// 当前透明度列表
let curOpaArray = []
// 当前高度列表
let curIndArray = []
let left = 0
// 是否可点击,控制点击频率
let canClick = true
// px和rpx转换比例,用于横向滑动的时候计算滑动距离(rpx)
let screenRate = 1
Page({
data: {
imgArray: [{
image:'imgs/image1.png',
text:'页面1'
},{
image:'imgs/image2.png',
text:'页面2'
},{
image:'imgs/image3.png',
text:'页面3'
}],
animation: [],
indexArray: [2,1,1]
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
wx.getSystemInfo({
success: (res) => {
screenRate = 750 / res.screenWidth
}
})
this.animation = []
for (let i = 0; i < 3; i++) {
let animation = wx.createAnimation({
duration: 500,
timingFunction: 'ease-out',
})
this.animation.push(animation)
}
},
touchstart(e) {
left = e.touches[0].pageX
},
touchmove(e) {
if (this.isMove) {
return
}
let moveLength = (e.touches[0].pageX - left) * screenRate
moveLength = moveLength > 60 ? 60 : moveLength
moveLength = moveLength < -60 ? -60 : moveLength
let rate = moveLength / 60
if (rate == 1) { //从右往左滑
this.isMove = true
this.tapLeft()
} else if (rate == -1) { //从左往右滑
this.isMove = true
this.tapRight()
}
},
touchend(e) {
setTimeout(()=>{
this.isMove = false
},500)
},
// 往左移
tapLeft() {
if (!canClick) {
return
}
canClick = false
setTimeout(() => {
canClick = true
}, 500)
curPosArray = this.rollRight(posArray, 1)
curScaArray = this.rollRight(scaArray, 1)
curOpaArray = this.rollRight(opaArray, 1)
curIndArray = this.rollRight(indArray, 1)
let animation = this.data.animation
for (let j = 0; j < 3; j++) {
this.animation[j].scale(curScaArray[j], curScaArray[j]).left(curPosArray[j] + 'rpx').opacity(curOpaArray[j]).step()
animation[j] = this.animation[j].export()
}
this.setData({
animation: animation,
indexArray: curIndArray
})
},
tapRight() {
if (!canClick) {
return
}
canClick = false
setTimeout(() => {
canClick = true
}, 500)
curPosArray = this.rollLeft(posArray, 1)
curScaArray = this.rollLeft(scaArray, 1)
curOpaArray = this.rollLeft(opaArray, 1)
curIndArray = this.rollLeft(indArray, 1)
let animation = this.data.animation
for (let j = 0; j < 3; j++) {
this.animation[j].scale(curScaArray[j], curScaArray[j]).left(curPosArray[j] + 'rpx').opacity(curOpaArray[j]).step()
animation[j] = this.animation[j].export()
}
this.setData({
animation: animation,
indexArray: curIndArray
})
},
rollLeft: function(array, times) {
for (let time = 0; time < times; time++) {
let length = array.length - 1
let temp = array[0]
for (let i = 0; i < length; i++) {
array[i] = array[i + 1]
}
array[length] = temp
}
return array.concat()
},
rollRight: function(array, times) {
for (let time = 0; time < times; time++) {
let length = array.length - 1
let temp = array[length]
for (let i = length; i > 0; i--) {
array[i] = array[i - 1]
}
array[0] = temp
}
return array.concat()
},
})
<view class="swiper-body" bindtouchmove="tauchMove" bindtouchstart="tauchStart" bindtouchend="tauchEnd">
<view class=".swiper-item-box {{item.zIndex==1?'none':''}}" wx:for="{{swiperList}}" wx:key="index" style="--index:{{item.zIndex}};--left:{{item.mLeft}}">
<view class="swiper-item">
<image src="{{item.url}}" mode="aspectFill" wx:if="{{item.type=='image'}}"></image>
<view class="photo-item-layout">
<view class="photo-item-title">标题</view>
<view class="photo-item-label">标签 </view>
</view>
</view>
</view>
</view>
page {
background-color: #fff;
}
.swiper-body {
height: 420rpx;
position: relative;
max-width: 750rpx;
overflow: hidden;
box-sizing: border-box;
margin-top: 90rpx;
}
.swiper-item-box {
position: absolute;
width: 300rpx;
height: 380rpx;
top: 0;
bottom: 0;
left: 50%;
margin: auto;
transition: all 0.2s ease-in 0s;
opacity: 1;
box-shadow: 0px 13rpx 12rpx rgba(0, 0, 0, .5);
border-radius: 15rpx;
overflow: hidden;
transform: scale(calc(0.5 + var(--index) / 10));
margin-left: calc(var(--left) * 100rpx - 150rpx);
z-index: var(--index);
}
.swiper-item-box.none {
opacity: 0;
}
.swiper-item {
overflow: hidden;
position: relative;
width: 100%;
height: 100%;
border-radius: 6rpx;
}
.swiper-item image{
width: 100%;
display: block;
height: 100%;
margin: 0;
pointer-events: none;
}
image {
max-width: 100%;
display: inline-block;
position: relative;
z-index: 0;
}
.photo-item-layout {
position: absolute;
width: 100%;
left: 0;
bottom: 0;
color: #fff;
border-bottom-right-radius: 18rpx;
float: left;
display: flex;
flex-direction: column;
background: linear-gradient(180deg, #0092fb00,#3691FB );
}
.photo-item-title {
color: white;
font-size: 32rpx;
font-weight: 800;
margin-top: 20rpx;
text-align: center;
overflow: hidden;
text-overflow: -o-ellipsis-lastline;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
.photo-item-label {
color: rgba(255, 255, 255, 0.829);
font-size: 28rpx;
text-align: center;
padding: 3rpx 20rpx 10rpx 20rpx;
border-top-right-radius: 20rpx;
border-bottom-right-radius: 20rpx;
overflow: hidden;
text-overflow: -o-ellipsis-lastline;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
Page({
data: {
swiperList: [
{
type: 'image',
url: '/img_fj.png'
}, {
type: 'image',
url: '/img_banner_random.png',
}, {
type: 'image',
url: '/img_activity.png'
}, {
type: 'image',
url: '/img_activity.png'
},
{
type: 'image',
url: '/img_stage.png'
},
{
type: 'image',
url: '/img_activity.png'
},
],
},
onLoad: function (options) {
this.tauchSwiper('swiperList');
},
onShow: function () {
},
// 初始化tauchSwiper
tauchSwiper(name) {
let list = this.data[name];
for (let i = 0; i < list.length; i++) {
// Math.abs(x) 函数返回指定数字 “x“ 的绝对值
list[i].zIndex = parseInt(list.length / 2) + 1 - Math.abs(i - parseInt(list.length / 2))
list[i].mLeft = i - parseInt(list.length / 2)
}
this.setData({
swiperList: list
})
},
// tauchSwiper触摸开始
tauchStart(e) {
this.setData({
tauchStart: e.touches[0].pageX
})
},
// tauchSwiper计算方向
tauchMove(e) {
this.setData({
direction: e.touches[0].pageX - this.data.tauchStart > 0 ? 'right' : 'left'
})
},
// tauchSwiper计算滚动
tauchEnd(e) {
let direction = this.data.direction;
let list = this.data.swiperList;
if (direction == 'right') {
let mLeft = list[0].mLeft;
let zIndex = list[0].zIndex;
for (let i = 1; i < list.length; i++) {
list[i - 1].mLeft = list[i].mLeft
list[i - 1].zIndex = list[i].zIndex
}
list[list.length - 1].mLeft = mLeft;
list[list.length - 1].zIndex = zIndex;
this.setData({
swiperList: list
})
} else {
let mLeft = list[list.length - 1].mLeft;
let zIndex = list[list.length - 1].zIndex;
for (let i = list.length - 1; i > 0; i--) {
list[i].mLeft = list[i - 1].mLeft
list[i].zIndex = list[i - 1].zIndex
}
list[0].mLeft = mLeft;
list[0].zIndex = zIndex;
this.setData({
swiperList: list
})
}
}
})
<view class="pageLayout">
<swiper indicator-dots='true' autoplay='true' interval='5000' duration='1000' circular='true'>
<block wx:for="{{bnrUrl}}" wx:for-index="index">
<swiper-item id='{{index}}' bindtap='bannerClick' data-bannertitle='{{item.title}}' data-bannerid='{{item.id}}'>
<image class='bannerLayout' src='{{item.url}}' mode='scaleToFill'></image>
</swiper-item>
</block>
</swiper>
</view>
/* 页面样式 */
.pageLayout {
background-size: 100%;
padding: 0 30rpx 50rpx;
}
/* 轮播图 */
.bannerLayout {
width: 100%;
height: 310rpx;
box-sizing: border-box;
overflow: hidden;
border-radius: 20rpx;
margin-top: 30rpx;
margin-bottom: 24rpx;
box-shadow: 0 0 10rpx #7d7d7d;
background: #fff;
}
// pages/banner2/banner2.js
const utils = require('../../utils/util.js');
Page({
/**
* 页面的初始数据
*/
data: {
"bnrUrl": [{
"url": `weChatFile/icon_menu_yxt.png`,
"title": `标题一`
}, {
"url": `weChatFile/icon_menu_yxt.png`,
"title": `标题二 `
}]
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
let that = this
that.getslideImg()
},
bannerClick: function (e) {
var bannerId = e.currentTarget.dataset.bannerid;
wx.navigateTo({
//方法一
url: '../bannerDetail/bannerDetail?bannerId='+bannerId,
//方法二
//url: `../bannerDetail/bannerDetail?bannerId=${bannerId}`,
})
},
getslideImg: function () {
let that = this
// utils.getPostData('a/msmallapp/appWheel/list', function (res) {
// let resData = res.data
// console.log("===3==" + resData);
// console.log(resData);
// if (resData) {
// if (resData.success) {
// let resList = resData.body.list
// that.setData({
// bnrUrl: resList
// })
// }
// }
// })
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
<!--index.wxml-->
<view class="container">
<!-- 轮播图 -->
<view class="banner-swiper">
<swiper indicator-dots="{{indicator}}" autoplay="{{autoplay}}" current='{{swiperCurrent}}' indicator-color="{{beforeColor}}" indicator-active-color="{{afterColor}}" circular='{{circular}}' previous-margin="{{previousmargin}}" next-margin="{{nextmargin}}"
bindchange="swiperChange">
<block wx:for="{{arr}}" wx:key="key">
<swiper-item>
<image src="{{item.images}}" class="slide-image {{index == swiperCurrent ? ' active' : ''}}"></image>
<view class='goods-info'>{{item.title}}</view>
<view class='goods-more'>
<view>
<text class='prefix'>免费样品</text>
<text class='nums'>({{item.num}}个)</text>
</view>
<view>
<text class='prefix supply'>供应价:</text>
<text class='price'>¥{{item.price}}</text>
</view>
</view>
</swiper-item>
</block>
</swiper>
<view class="dots">
<block wx:for="{{arr}}" wx:key="{{index}}">
<view class="{{index== cur?'active':''}} dot"></view>
</block>
</view>
</view>
</view>
/**index.wxss**/
/* 轮播图 */
.banner-swiper{
width: 100%;
height: 540rpx;
overflow: hidden;
position: relative;
background-color: #fff;
}
swiper {
display: block;
height: 540rpx;
font-size: 0;
}
.slide-image{
width: 96%;
display: block;
margin: 0 auto;
height: 410rpx;
border-radius: 10rpx;
font-weight: bold;
}
.goods-info{
font-size: 28rpx;
color: #000;
text-align: center;
margin-top: 20rpx;
margin-bottom: 20rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.goods-more {
display: flex;
flex-direction: row;
justify-content: center;
}
.supply {
margin-left: 40rpx;
}
.prefix {
font-size: 24rpx;
color: #000;
}
.nums {
font-size: 24rpx;
color: #666;
}
.price {
font-size: 24rpx;
color: #fc515c;
}
.dots{
position: absolute;
right: 0;
bottom: 140rpx;
left: 0;
width: 300rpx;
height: 18rpx;
margin: 0 auto;
text-align: center;
display: flex;
flex-direction: row;
justify-content: center;
}
/*未选中时的小圆点样式 */
.dot{
width: 10rpx;
height: 10rpx;
margin-right: 8rpx;
border-radius: 100rpx;
background-color: #f2f2f2;
}
/*选中以后的小圆点样式 */
.active{
width: 36rpx;
height: 10rpx;
border-radius: 5rpx;
background-color: #f2f2f2;
}
//index.js
//获取应用实例
const app = getApp()
Page({
/**
* 页面的初始数据
*/
data: {
arr: [{
images: '/weChatFile/img_fj.png',
title: 'Lumea Prestige系列脱毛装置',
num: '2',
price: '99.00'
},
{
images: '/weChatFile/img_banner_random.png',
title: 'Lumea Prestige系列脱毛装置',
num: '2',
price: '99.00'
},
{
images: '/weChatFile/img_activity.png',
title: 'Lumea Prestige系列脱毛装置',
num: '2',
price: '99.00'
}],
beforeColor: "white",//指示点颜色
afterColor: "coral",//当前选中的指示点颜色
previousmargin: '24px',//前边距
nextmargin: '24px',//后边距
indicator: false, //是否显示指示点
interval: 5000, //自动切换时间间隔
duration: 400, //滑动动画时长
autoplay: true, //是否自动切换
circular: true, //是否采用衔接滑动
cur: 0, //当前所在滑块的index
},
//轮播图的切换事件
swiperChange(e) {
let cur = e.detail.current //获取当前轮播图片的下标, 可以给当前指示点加样式
this.setData({
cur: cur
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})