You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React中用FLIP技术实现点击子内容与主内容互换位置的布局

核心问题定位

你之前的实现有两个核心错误:

  • 为每个卡片单独维护激活状态,无法建立「子卡片和主卡片交换」的联动逻辑
  • Flipper的flipKey参数传入了逗号表达式active,active1,逗号表达式只会返回最后一个值,无法正确触发对应元素的FLIP动画

实现思路

  1. 统一用数组存储所有内容块的数据,约定数组第一位对应主内容区,剩余元素对应子内容区
  2. 仅用一个状态记录当前选中交换的元素索引,点击子元素时交换数组中第一位和点击位置的元素
  3. flipKey绑定数组元素的唯一标识(或直接绑定主内容的id),只要数组顺序变化就会触发FLIP计算

完整实现代码

import { useState } from 'react';
import { Flipper, Flipped } from 'react-flip-toolkit';
import './styles.css';

// 模拟内容块数据,每个元素带唯一id和内容
const initCards = [
  { id: 'main', content: '主内容区', isMain: true },
  { id: 'sub1', content: '子内容区1', isMain: false },
  { id: 'sub2', content: '子内容区2', isMain: false },
  { id: 'sub3', content: '子内容区3', isMain: false },
];

export default function App() {
  const [cards, setCards] = useState(initCards);

  const handleCardClick = (clickIndex) => {
    // 点击的是主内容区直接返回
    if (clickIndex === 0) return;
    // 交换主内容区(索引0)和点击位置的元素
    const newCards = [...cards];
    [newCards[0], newCards[clickIndex]] = [newCards[clickIndex], newCards[0]];
    setCards(newCards);
  };

  return (
    <div className="container">
      {/* flipKey绑定主内容id,交换后id变化就会触发动画 */}
      <Flipper flipKey={cards[0].id} spring="gentle">
        {/* 主内容区渲染 */}
        <div className="main-area">
          <Flipped flipId={cards[0].id}>
            <div
              className="main-card"
              onClick={() => handleCardClick(0)}
            >
              {cards[0].content}
            </div>
          </Flipped>
        </div>
        {/* 子内容区列表渲染 */}
        <div className="sub-area-list">
          {cards.slice(1).map((card, index) => (
            <Flipped flipId={card.id} key={card.id}>
              <div
                className="sub-card"
                onClick={() => handleCardClick(index + 1)}
              >
                {card.content}
              </div>
            </Flipped>
          ))}
        </div>
      </Flipper>
    </div>
  );
}

对应的CSS示例:

.container {
  width: 800px;
  margin: 20px auto;
  display: flex;
  gap: 20px;
}
.main-area {
  width: 60%;
}
.main-card {
  width: 100%;
  height: 400px;
  background: #2196F3;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  cursor: pointer;
  font-size: 20px;
}
.sub-area-list {
  width: 40%;
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.sub-card {
  width: 100%;
  height: 120px;
  background: #4CAF50;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  cursor: pointer;
  font-size: 16px;
}

逻辑说明

  • 所有Flipped组件的flipId和内容块的唯一id绑定,保证每个元素的身份标识唯一
  • 点击子内容区时仅交换数组顺序,不需要单独维护每个元素的位置样式,FLIP库会自动计算位置变化生成过渡动画
  • 不需要为每个子内容单独维护状态,统一通过数组顺序控制主/子内容的位置,可支持任意数量的子内容扩展

内容的提问来源于stack exchange,提问作者GUERU

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 03:27:01