更新记录

1.0.0(2026-08-31) 下载此版本

  • 核心手势引擎:发布首个正式版本,内置丝滑物理拖拽手势与 0.05 黄金跟手旋转阻尼。
  • 多维空间堆叠:支持配置垂直偏移步长 (offsetY)、水平偏移步长 (offsetX)、缩放步长 (scaleStep)、错落旋转步长 (rotateStep) 以及透明度渐隐衰减 (fadeStep)。
  • 灵活模式支持:支持无限循环翻页 (loop: true) 与单次滑完判定 (loop: false)。
  • 交互防护机制:退场飞出卡片与底层未激活卡片全面隔离事件流 (pointer-events: none),杜绝误触与穿透形变。
  • 丰富插槽透传:支持通过作用域插槽获取 item、dragRatio、dragDirection 等实时拖拽动力学数据。
  • 完整 API 与实例方法:支持通过 ref 实例方法进行编程式切牌 (swipe) 与状态归位 (reset)。

平台兼容性

uni-app(3.8.3)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
× √ √ √ √ × √ √ √
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
√ √ √ √ √ √ √ √ √ √ √ √

jon-stack 卡片堆叠滑动组件

通用高性能卡片堆叠滑动容器,内置丝滑手势拖动与物理联动动画,支持图片背景或纯色背景作为卡片底图,并在上层提供完全自定义内容插槽,可配置任意层叠布局,开箱即用。

适用于「探探式」滑动卡片、商品推荐、图片浏览、短视频推荐等场景。


特性

  • 🎯 丝滑手势引擎:内置物理拖拽手势与 0.05 黄金跟手旋转阻尼,拖动、判定、飞出一气呵成
  • 🗂 多维空间堆叠:独立配置垂直偏移 offsetY、水平偏移 offsetX、缩放 scaleStep、错落旋转 rotateStep、透明度渐隐 fadeStep,任意排列组合
  • 🔁 双模式切换:loop: true 无限循环翻页 / loop: false 单次滑完并触发 end 事件
  • 🛡 交互隔离防护:退场飞出卡片与底层未激活卡片全面隔离事件流(pointer-events: none),杜绝误触与穿透形变
  • 🎨 背景与插槽叠加:图片背景(imageKey)或纯色背景(bgKey)作为卡片底图,上层始终渲染完全自定义内容插槽;二者可同时使用,也可以都不设置背景
  • 📦 作用域插槽透传:实时获取 item、index、isCurrent、dragRatio、dragDirection 等拖拽动力学数据
  • 🎛 完整 API:ref 实例方法编程式切牌 swipe()、状态归位 reset()

安装

在 HBuilderX 中,将本插件目录(uni_modules/jon-stack)拷贝到项目的 uni_modules 目录下即可。

组件符合 easycom 规范,无需手动 import 与注册,页面中直接使用 <jon-stack /> 标签。


快速上手

<template>
    <view class="page">
        <jon-stack ref="stackRef" :list="cardList" @change="onChange" @swipe="onSwipe"
            @cardClick="onCardClick" @end="onEnd">
            <template #default="{ item }">
                <view class="card-body">
                    <text class="card-text">{{ item.title }}</text>
                </view>
            </template>
        </jon-stack>

        <view class="actions">
            <button @click="swipe('left')">左滑</button>
            <button @click="reset">重置</button>
            <button @click="swipe('right')">右滑</button>
        </view>
    </view>
</template>

<script setup>
    import { ref } from 'vue'

    const stackRef = ref(null)

    const cardList = ref([
        { id: 1, title: '卡片 1', image: '/static/1.jpg' },
        { id: 2, title: '卡片 2', bgColor: '#66ccff' },
        { id: 3, title: '卡片 3' }
    ])

    const onChange = (e) => {
        console.log('当前项:', e.current, e.item)
    }

    const onSwipe = (e) => {
        console.log('划出方向:', e.direction, '卡片:', e.item)
    }

    const onCardClick = (e) => {
        console.log('点击卡片:', e.item)
    }

    const onEnd = (e) => {
        console.log('全部滑完,共', e.total, '张')
    }

    const swipe = (dir) => stackRef.value?.swipe(dir)
    const reset = () => stackRef.value?.reset()
</script>

<style scoped>
    .page {
        padding: 60rpx 32rpx;
    }

    .card-body {
        width: 100%;
        height: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .card-text {
        font-size: 38rpx;
        font-weight: bold;
        color: #ffffff;
        text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.4);
    }

    .actions {
        display: flex;
        gap: 16rpx;
        margin-top: 80rpx;
    }
</style>

API

Props 属性

属性 类型 默认值 必填 说明
list Array [] 是 数据源列表,数组项为卡片数据对象
width String '680rpx' 否 卡片宽度,支持任意 CSS 尺寸
height String '860rpx' 否 卡片高度,支持任意 CSS 尺寸
borderRadius String '32rpx' 否 卡片圆角
shadow String '0 16rpx 48rpx rgba(0, 0, 0, 0.12)' 否 卡片阴影
imageKey String 'image' 否 数据项中图片字段的属性名(用于读取卡片底图)
imageMode String 'aspectFill' 否 图片裁剪缩放模式,同 uni-app image 组件 mode
bgKey String 'bgColor' 否 数据项中背景色字段的属性名
visibleCount Number 3 否 可见层数,取值范围 1 ~ 5
offsetY Number 36 否 垂直偏移步长(rpx),正数向下、负数向上、0 不位移
offsetX Number 0 否 水平偏移步长(rpx),正数向右、负数向左、0 不位移
scaleStep Number 0.05 否 缩放步长,正数逐层缩小、负数逐层放大、0 等大
rotateStep Number 0 否 层叠错落旋转步长(deg),正数顺时针、负数逆时针
transformOrigin String 'center center' 否 缩放 / 旋转基准中心点,如 'center bottom'
fadeStep Number 0 否 层级透明度衰减步长,取值 0 ~ 1,越大后层越透明
duration Number 300 否 动画过渡耗时(ms)
timingFunction String 'cubic-bezier(0.25, 1, 0.5, 1)' 否 缓动动画曲线,可传任意 CSS 过渡函数
threshold Number 80 否 判定滑出卡片的物理像素距离(px)
loop Boolean true 否 是否无限循环滑动,false 时滑完触发 end 事件
disabled Boolean false 否 是否禁用滑动交互与点击(true 时锁定卡片)

Events 事件

事件名 触发时机 回调参数
change 当前卡片切换(含编程式 swipe()) { current, item, direction } — 当前项索引、当前项数据、划出方向 'left' / 'right'
swipe 卡片划出(手势或编程式) { direction, item, index } — 划出方向、划出卡片数据、在原始列表中的索引
cardClick 点击当前卡片(位移小于 5px 视为点击) { item, index } — 卡片数据、在原始列表中的索引
end 非循环模式下全部卡片滑完 { total } — 卡片总数

Slots 插槽

默认作用域插槽,用于完全自定义卡片内容,插槽容器铺满整张卡片:

插槽参数 类型 说明
item Object 当前卡片数据
index Number 当前卡片数据在原始列表中的索引(取模回绕后的值)
isCurrent Boolean 是否为当前最上层卡片
isNext Boolean 是否为下一张即将切换的卡片
absoluteIndex Number 卡片在渲染队列中的绝对索引(内部用)
dragRatio Number 当前卡片拖拽进度 0 ~ 1(仅当前卡片实时更新)
dragDirection String 当前拖拽方向:'left' / 'right' / 'none'

实例方法

通过 ref 获取组件实例后调用:

方法 参数 说明
swipe(direction) direction?: 'left' \| 'right',默认 'right' 编程式触发卡片划出动画,会同步触发 swipe / change / end 事件
reset() 无 重置卡片索引与拖拽位移状态,回到第一张卡片

数据项字段与插槽叠加

组件通过 imageKey 与 bgKey 从数据项读取底图与背景色,并在其上层渲染默认插槽内容。图片/背景色作为卡片底层背景,插槽作为上层内容,二者可同时存在、互不冲突:

// 图片背景 + 插槽文字
{ id: 1, title: '图片卡', image: 'https://xxx/1.jpg' }

// 纯色背景 + 插槽内容
{ id: 2, title: '纯色卡', bgColor: '#66ccff' }

// 不设置背景:透明卡片,仅使用自定义插槽
{ id: 3, title: '自定义卡' }

常见布局推荐参数

组件本身不内置任何预设布局,以下参数组合来自示例工程的实践,可直接复用:

布局效果 参数组合
经典底部堆叠 offsetY=36, offsetX=0, rotateStep=0
顶部展开 offsetY=-36, offsetX=0, rotateStep=0
右侧展开 offsetY=0, offsetX=36, rotateStep=0
斜向错落 offsetY=24, offsetX=24, rotateStep=3
居中重叠 offsetY=0, offsetX=0, rotateStep=0
扇形旋转 offsetY=0, offsetX=0, rotateStep=6

注意事项

  1. 版本要求:本组件源码使用 Vue3 <script setup> 语法,推荐用于 uni-app Vue3 项目;HBuilderX 需 3.1.0+(与 package.json 中 engines.HBuilderX 一致)。如需在 Vue2 中使用,需自行转换为 Options API 写法。
  2. 容器尺寸:组件默认 margin: 0 auto 居中,尺寸由 width / height 控制,请为容器预留足够空间。
  3. 触摸冲突:组件内部已设置 touch-action: none,若外层页面需要纵向滚动,请将组件放置在独立容器中,并合理控制卡片拖拽方向。
  4. 数据更新:动态增删 list 数据时,建议在变更后调用 reset() 使卡片状态归位。
  5. 图片字段:若数据项中无图片字段(或图片为空),组件自动跳过图片渲染,不影响插槽内容。
  6. 点击事件:需要区分「轻触点击」与「拖拽滑动」时,建议监听 cardClick 事件;插槽内自定义元素仍可正常绑定点击事件,但需注意与拖拽手势的冲突。

更新日志

详见 changelog.md。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

无

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

许可协议

MIT协议

暂无用户评论。