SL-WX-FlipCard 翻转卡片组件
2026/9/8 17:39:13 网站建设 项目流程

SL-WX-FlipCard 翻转卡片组件

插件市场
操作视频

组件简介

基于 CSS Transform 体系实现的点击翻转卡片组件。内置7 种切换动画(左右翻转、上下翻转、旋风旋转、淡入淡出、底部滑入、右侧滑入、缩放切换),支持单列 / 多列网格布局、互斥展开(一次只翻一张)、正/背面插槽自定义、批量翻转与还原的对外 API。H5 / 微信小程序通用。

修复说明:在部分 WebView / 小程序环境下backface-visibility: hidden仅视觉透明,仍会拦截二次点击。组件已通过opacity + visibility + pointer-events三重控制 + 动画半程切换策略彻底解决「翻转后点不回来」的问题,7 种动画全部通过同一可见性机制保障交互一致性。

目录结构

components/SL-WX-FlipCard └── SL-WX-FlipCard.vue

核心特性

  • 7 种内置动画:通过animation属性切换,涵盖 3D 翻牌类(flipY / flipX)、2D 趣味类(rotate)、轻量类(fade)、滑动类(slideUp / slideLeft)、透视缩放类(zoom)共 7 种风格。3D 类动画自动启用perspective + preserve-3d,2D 类动画自动关闭 3D 上下文以减少合成层开销。

  • 单列 / 多列自由切换columnCount设置列数(1~N),内部使用 CSS Grid 自适应排列,列间距、行间距、外层内边距均可独立配置。

  • 点击翻转(全端统一):点击任意卡片在正/背面之间切换,H5 与小程序行为完全一致;所有动画均保证"翻转后二次点击必定翻回"。

  • 互斥展开exclusive = true时,一次只能有一张卡片处于背面,适合「问答」「翻牌游戏」「单选卡片」等场景。

  • 任意宽高比:通过aspectRatio(如1 / 116 / 101 / 1.2)控制卡片形状。

  • 正/背面内容完全自定义:默认根据数据 key 自动渲染「图片 + 底部渐变标题/描述」,也可通过#front/#back具名插槽完全重写。

  • 无图模式自动适配:未提供图片字段时,正面白底深色字,背面浅灰底蓝字,居中对齐显示纯文字。

  • 对外方法:暴露flip(index, flipped)reset(),通过$refs调用。

动画类型一览(animationprop)

动画值名称类型效果说明适用场景
flipY左右翻转3D沿垂直中线做 Y 轴 180° 翻转(经典扑克牌翻牌),默认动画商品卡片 / 相册 / 记忆翻牌游戏
flipX上下翻转3D沿水平中线做 X 轴 180° 翻转答题卡 / 门票/票据
rotate旋风旋转2D绕中心旋转 180° 并搭配弹性缩放(cubic-bezier 回弹),正背面文字正向显示抽奖 / 转盘 / 活泼的运营位
fade淡入淡出2D正面淡出并放大至 1.1 倍,背面从 0.9 倍淡入至 1.0 倍相册 / 资讯 / 视觉温和的场景
slideUp底部滑入2D背面从卡片底部 100% 处滑入,正面同步向上滑出列表项详情 / 问答 / 提示卡
slideLeft右侧滑入2D背面从卡片右侧 100% 处滑入,正面同步向左滑出横向分页式卡片 / 翻页式展示
zoom缩放切换2D正面缩小至 0.2× 消失,背面从 0.2× 放大到 1.0× 出现(分阶段 opacity 平滑过渡)照片集 / 作品展示 / 主题切换卡片

小提示:同一页面多次切换animation时,建议先调用reset()清空所有卡片的翻转态,避免处于"半翻转"中间态时动画算法不同导致的错位感。

Props

属性类型默认值说明
listArray[]数据列表
columnCountNumber2列数,1为单列,2+为多列
animationString'flipY'动画类型:flipY/flipX/rotate/fade/slideUp/slideLeft/zoom
aspectRatioString'1 / 1'卡片宽高比(width / height),如'16 / 10''1 / 1.2'
durationNumber600动画时长(ms),可见性切换点自动取duration/2
radiusNumber16卡片圆角(rpx)
columnGapNumber20列间距(rpx)
rowGapNumber20行间距(rpx)
paddingNumber24外层容器内边距(rpx)
exclusiveBooleanfalse是否互斥展开,true时一次只能翻转一张
frontImageKeyString'frontImage'正面图片字段名
frontTitleKeyString'frontTitle'正面标题字段名
frontDescKeyString'frontDesc'正面描述字段名
backImageKeyString'backImage'背面图片字段名
backTitleKeyString'backTitle'背面标题字段名
backDescKeyString'backDesc'背面描述字段名

Events

事件名回调参数说明
itemtap{ item, index, flipped }点击卡片时触发,返回当前项数据、索引和翻转后的状态
onItemTap({item,index,flipped}){console.log('第'+index+'张,翻转后:'+flipped,item)}

Slots

插槽名作用域参数说明
front{ item, index }自定义卡片正面内容(覆盖默认的「图片+标题+描述」渲染)
back{ item, index }自定义卡片背面内容(覆盖默认的「图片+标题+描述」渲染)

对外方法

<sl-wx-flip-card ref="flip" :list="list" animation="zoom" />
方法名参数说明
flip(index?, flipped?)手动翻转。传index翻转指定卡片;不传(或传null)则作用于全部;flipped = true/false强制指定状态,不传则切换
reset-将所有卡片还原到正面
this.$refs.flip.flip(2,true)// 第 3 张翻到背面this.$refs.flip.flip(0)// 切换第 0 张this.$refs.flip.flip(null,true)// 全部翻开this.$refs.flip.reset()// 全部还原

使用示例

示例 1:2 列图片卡片 + 缩放动画(zoom)

<template> <sl-wx-flip-card ref="flip" :list="list" :column-count="2" animation="zoom" :aspect-ratio="'1 / 1'" :duration="550" :column-gap="16" :row-gap="16" @itemtap="onTap" /> </template> <script> import SlWxFlipCard from '@/components/SL-WX-FlipCard/SL-WX-FlipCard.vue' export default { components: { SlWxFlipCard }, data() { return { list: [ { frontImage: 'https://picsum.photos/seed/a/600/600', frontTitle: '雪山之境', frontDesc: '点击缩放查看', backImage: 'https://picsum.photos/seed/ab/600/600', backTitle: '喜马拉雅', backDesc: '海拔 8848 米,常年积雪。' }, { frontImage: 'https://picsum.photos/seed/b/600/600', frontTitle: '城市夜景', frontDesc: '霓虹闪烁', backImage: 'https://picsum.photos/seed/bb/600/600', backTitle: '上海外滩', backDesc: '万国建筑博览群。' } ] } }, methods: { onTap({ item, index, flipped }) { console.log(item, index, flipped) } } } </script>

示例 2:问答卡片 + 旋风动画(rotate) + 互斥

<template> <sl-wx-flip-card :list="qaList" :column-count="3" animation="rotate" :aspect-ratio="'1 / 1.2'" :exclusive="true" front-title-key="q" back-title-key="aTitle" back-desc-key="a" /> </template> <script> export default { data() { return { qaList: [ { q: '1+1=?', aTitle: '答案:2', a: '十进制加法的基础结果。' }, { q: '地球是圆的吗?', aTitle: '答案:是', a: '两极稍扁、赤道略鼓的椭球体。' }, { q: '水的化学式?', aTitle: '答案:H₂O', a: '2 个氢原子 + 1 个氧原子。' } ] } } } </script>

示例 3:横向滑入动画(slideLeft) + 单列大卡片

<template> <sl-wx-flip-card :list="list" :column-count="1" animation="slideLeft" :aspect-ratio="'16 / 10'" :radius="20" :duration="500" /> </template>

示例 4:淡入淡出 + 插槽自定义内容

<template> <sl-wx-flip-card :list="list" :column-count="2" animation="fade" :duration="500" > <template #front="{ item }"> <view class="front"> <image :src="item.cover" mode="aspectFill" class="front__img" /> <view class="front__tag">{{ item.tag }}</view> </view> </template> <template #back="{ item }"> <view class="back"> <text class="back__price">¥ {{ item.price }}</text> <text class="back__desc">{{ item.detail }}</text> <button size="mini" type="primary">立即购买</button> </view> </template> </sl-wx-flip-card> </template>

示例 5:外部控制 + 上下翻转(flipX)

<template> <view> <view class="btns"> <button @tap="$refs.flip.flip(null, true)">全部翻开</button> <button @tap="$refs.flip.flip(null, false)">全部正面</button> <button @tap="$refs.flip.reset()">全部还原</button> </view> <sl-wx-flip-card ref="flip" :list="list" :column-count="3" animation="flipX" /> </view> </template>

动画实现原理简述

所有 7 种动画共用同一套可见性切换机制,保证交互统一且不会出现"点不回来":

  1. 可见性切换时机visibilitypointer-events使用 0s duration 的 transition,延迟到duration/2执行——即在动画半程(卡片垂直于屏幕 / 两面都不可见的瞬间)完成事件命中面的切换。
  2. 正反双向延迟方向不同:未翻转 → 翻转过程中,前半程点击仍命中正面、后半程命中背面;反向同理,避免刚点下一瞬间被另一张面抢走事件。
  3. 3D 与 2D 的区分:外层.sl-flip-cell--3d(flipY / flipX)才加perspective: 1200px.sl-flip-cell--2d(其余 5 种)关闭,减少小程序 WebView 不必要的 GPU 合成层开销。

注意事项

  1. 3D 兼容性perspectivetransform-style: preserve-3dbackface-visibility已加-webkit-前缀。若低端 Android 机型在flipY / flipX下偶现闪烁,可缩短duration400~500ms,或改用 2D 动画(rotate / fade / slideX / zoom)。

  2. 切换动画时请 reset:运行中从一种动画切到另一种时(例如演示页的切换条),建议先调用$refs.flip.reset()把所有卡还原,避免处于翻转态的卡片因两套变换算法差异产生视觉"跳变"。

  3. 二次点击必响应:7 种动画均通过同一套opacity + visibility + pointer-events在半程(duration/2)切换命中面,保证正面 → 背面 → 再正面的完整循环链路畅通。

  4. 字段 key 映射:默认渲染依赖 6 个字段;若业务字段名不同,用frontImageKey等重映射或直接用#front / #back插槽自定义。

  5. 列数切换:动态改columnCount不会清已翻状态。若要切列数时一起重置,watch columnCount后调$refs.flip.reset()

  6. 互斥 + 批量 flipexclusive = trueflip(null, true)只会让最后一张翻转(语义约束)。若要全翻开,先把exclusivefalse

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询