微信小程序实现堆叠式轮播

1. 微信小程序实现堆叠式轮播

  初始需要给item们放置好位置以及各种层级,然后在切换滑动的过程中对设置的位置、层级、透明度进行替换,加上小程序的wx.createAnimation()动画效果。

1.1. 方案一

在这里插入图片描述

1.1.1. banner.xml

<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>

1.1.2 banner.wxss

<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>

1.1.3 banner.js

// 位置列表
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()
    },
})

1.2. 方案二

在这里插入图片描述

1.2.1. banner.wxml

<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>

1.2.3. banner.wxss

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;
}

1.2.3. banner.js


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
     })
   }
 }
})

1.3. 方案三

在这里插入图片描述

1.3.1. banner.wxml

<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>

1.3.2. banner.wxss

/* 页面样式 */
.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;
}


1.3.3. banner.js

// 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 () {

      }
})

1.4. 方案四

在这里插入图片描述

1.4.1. banner.wxml

<!--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>

1.4.2. banner.wxss

/**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;
}

1.4.3. banner.js

//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 () {
    
  }
})
  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值