1. 为什么你需要一个层叠轮播图?
如果你做过微信小程序,尤其是电商类的小程序,肯定对轮播图不陌生。传统的轮播图就是一张张图片平铺切换,虽然实用,但总觉得少了点视觉冲击力,用户看久了容易审美疲劳。我接手过好几个电商项目,产品经理总是提需求:“这个轮播图能不能做得更‘炫’一点?让用户一眼就看到主推商品。”
这时候,层叠轮播图就成了一个绝佳的选择。它把几张卡片像扑克牌一样层叠起来,只有中间那张是最大、最清晰的,两边的卡片会逐渐缩小并带有一定的偏移。当用户滑动时,卡片会像有惯性一样“流”过去,视觉焦点始终在中间那张图上。这种效果不仅好看,更重要的是,它能非常直观地引导用户的注意力,非常适合用来展示商品的主次关系,比如一个系列里的主打款和搭配款。
你可能在网上搜到过一些方案,有的建议用复杂的CSS 3D变换,有的甚至说要引入第三方动画库。但实测下来,对于微信小程序这种相对轻量的环境,最稳、最兼容的方案,还是基于小程序原生的 swiper组件 进行改造。没错,就是那个我们最熟悉的、用来做基础轮播的swiper。通过一些巧妙的样式动态切换,我们完全可以用它模拟出非常流畅的层叠效果,而且性能开销极小,在老款手机上也能跑得很顺畅。
接下来的内容,我会把我踩过的坑和总结的最佳实践,一步步拆开给你看。即使你之前只写过基础的swiper,跟着我的思路走,也能在半小时内做出一个效果惊艳的动态层叠轮播图。
2. 核心思路拆解:动态样式与层级管理
在开始写代码之前,我们得先把脑子里的“效果图”翻译成小程序能理解的逻辑。层叠效果的核心,其实就是两件事:层级(z-index) 和 变形(transform)。
想象一下五张卡片平铺在桌面上,你想让它们层叠起来。你会把中间那张拿起来放到最上面(z-index最高),同时把左右两边的卡片往中间推一点,并且缩小一些(transform: translateX & scale)。对于更边缘的卡片,则推得更远、缩得更小。这就是我们想要实现的静态效果。
但轮播图是动态的,卡片会滑动。所以,我们不能把样式写死。关键在于:每一张卡片的样式,都不是固定的,而是取决于“它当前是不是中间那张激活的卡片”。当滑动发生时,我们需要迅速判断出新的“中间卡”是谁,然后给所有卡片重新计算并应用一套新的样式规则。
原始文章里提到了一个非常重要的点,也是新手最容易搞混的地方:这里“激活的项”指的是视觉上中间最大的那一项,而不是swiper组件默认的current(最左侧的那一项)。因为我们要显示5张卡片(display-multiple-items=“5”),所以视觉中心是第三张。这个概念的区分至关重要,后面所有计算都是围绕“视觉中心索引”而不是“swiper当前索引”展开的。
我的实现方案可以概括为以下三步,这个流程你在任何类似需求中都可以复用:
- 结构搭建:用
<swiper>包裹多个<swiper-item>,这是容器。 - 样式分层:为不同位置的卡片(中间、左右相邻、更远)预先写好多套CSS样式,定义好它们的缩放大小、水平偏移和层级高度。
- 动态裁决:在swiper滑动时,通过一个判断函数,实时为每一个
<swiper-item>和它内部的视图“裁决”出应该应用哪一套样式类。
这个“裁决官”就是我们将要编写的WXS函数。它根据当前滑动的状态,告诉每个卡片:“嘿,你现在是老大(中间),请用‘老大’的样式”,或者“你是老大的左护法,请用‘左护法’的样式”。这样,我们就把动态的视觉效果和静态的样式代码解耦了,逻辑非常清晰。
3. 从零开始:搭建基础结构与样式
理论说再多不如动手。我们先来把轮播图的骨架和皮肤搭好。这里我会给出详细的代码和参数解释,你可以直接复制过去修改。
首先是小程序页面的WXML结构。我们使用一个标准的swiper,并开启循环播放(circular)和自动播放(autoplay),同时一次显示5张卡片。
<!-- index.wxml -->
<view class="container">
<swiper
class="stack-swiper"
display-multiple-items="5"
circular="{
{true}}"
autoplay="{
{true}}"
interval="3000"
duration="500"
bindchange="onSwiperChange"
easing-function="easeOutCubic"
>
<block wx:for="{
{imageList}}" wx:key="id">
<swiper-item
class="swiper-item {
{swiperUtils.getItemZIndex(index, activeIndex, imageList.length)}}"
>
<view
class="card {
{swiperUtils.getCardClass(index, activeIndex, imageList.length)}}"
style="background

100

被折叠的 条评论
为什么被折叠?



