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

如何在NextJS应用中创建动态影院选座布局

实现NextJS影院动态选座布局方案

1. 定义结构化的座位数据

要支持不同影院的动态布局,首先需要后端返回结构化的座位数据,每个影厅的座位可以用包含行信息的数组表示,每个座位包含状态标识:

// 示例座位数据结构(可从API获取)
const sampleTheaterSeats = [
  { row: "A", seats: [{ id: "A1", status: "available" }, { id: "A2", status: "sold" }, { id: "A3", status: "available" }] },
  { row: "B", seats: [{ id: "B1", status: "sold" }, { id: "B2", status: "available" }, { id: "B3", status: "available" }, { id: "B4", status: "sold" }] },
  { row: "C", seats: Array.from({ length: 5 }, (_, i) => ({ id: `C${i+1}`, status: Math.random() > 0.3 ? "available" : "sold" })) }
];
  • status 字段用 sold(已售出)/ available(可预订)区分状态

2. 拆分组件实现复用

基于NextJS的组件化思想,拆分出三个核心组件:

单个座位组件(Seat.jsx)

负责渲染单个座位,根据状态应用样式:

export default function Seat({ seat, onSelect }) {
  const seatClasses = seat.status === "sold" 
    ? "bg-yellow-500 cursor-not-allowed" 
    : "bg-white border-gray-300 hover:bg-gray-200 cursor-pointer";

  return (
    <button
      className={`w-8 h-8 rounded-md mx-1 ${seatClasses}`}
      disabled={seat.status === "sold"}
      onClick={() => seat.status === "available" && onSelect(seat.id)}
    >
      {seat.id}
    </button>
  );
}

座位行组件(SeatRow.jsx)

渲染整行座位,包含行号标识:

import Seat from "./Seat";

export default function SeatRow({ row, onSelect }) {
  return (
    <div className="flex items-center mb-2">
      <span className="w-8 text-right mr-2 font-medium">{row.row}</span>
      <div className="flex">
        {row.seats.map(seat => (
          <Seat key={seat.id} seat={seat} onSelect={onSelect} />
        ))}
      </div>
    </div>
  );
}

整体布局组件(TheaterLayout.jsx)

整合屏幕、座位区和图例,是页面的核心展示组件:

import SeatRow from "./SeatRow";

export default function TheaterLayout({ seatsData, selectedSeats, onSelect }) {
  return (
    <div className="flex flex-col items-center p-4">
      {/* 屏幕区域 */}
      <div className="w-3/4 h-8 bg-gray-800 mb-8 rounded-md flex items-center justify-center text-white">
        屏幕
      </div>

      {/* 座位区域 */}
      <div className="space-y-2">
        {seatsData.map(row => (
          <SeatRow key={row.row} row={row} onSelect={onSelect} />
        ))}
      </div>

      {/* 状态图例 */}
      <div className="flex items-center mt-8 space-x-6">
        <div className="flex items-center">
          <div className="w-6 h-6 bg-yellow-500 rounded-md mr-2"></div>
          <span>已售出</span>
        </div>
        <div className="flex items-center">
          <div className="w-6 h-6 bg-white border border-gray-300 rounded-md mr-2"></div>
          <span>可预订</span>
        </div>
        {selectedSeats.length > 0 && (
          <div className="flex items-center">
            <div className="w-6 h-6 bg-blue-500 rounded-md mr-2"></div>
            <span>已选中</span>
          </div>
        )}
      </div>
    </div>
  );
}

3. 页面层动态获取数据

在NextJS页面中,根据影院ID从API获取对应座位数据,传递给布局组件:

// pages/theaters/[theaterId].jsx
import { useEffect, useState } from "react";
import TheaterLayout from "../../components/TheaterLayout";

export default function TheaterSeatPage({ theaterId }) {
  const [seatsData, setSeatsData] = useState([]);
  const [selectedSeats, setSelectedSeats] = useState([]);

  // 获取影院座位数据
  useEffect(() => {
    const fetchSeats = async () => {
      const res = await fetch(`/api/theaters/${theaterId}/seats`);
      const data = await res.json();
      setSeatsData(data);
    };
    fetchSeats();
  }, [theaterId]);

  // 处理选座逻辑
  const handleSeatSelect = (seatId) => {
    setSelectedSeats(prev => 
      prev.includes(seatId) ? prev.filter(id => id !== seatId) : [...prev, seatId]
    );
  };

  if (!seatsData.length) return <div className="text-center py-8">加载中...</div>;

  return (
    <div className="container mx-auto py-8">
      <h1 className="text-2xl font-bold mb-6 text-center">选择您的座位</h1>
      <TheaterLayout 
        seatsData={seatsData} 
        selectedSeats={selectedSeats} 
        onSelect={handleSeatSelect} 
      />
    </div>
  );
}

// 服务器端渲染获取影院ID
export async function getServerSideProps(context) {
  const { theaterId } = context.params;
  return { props: { theaterId } };
}

4. 样式说明

示例中使用Tailwind CSS实现样式,如果你用CSS模块,只需将类名替换为对应的自定义样式即可:

  • 已售出座位:黄色背景,禁用状态
  • 可预订座位:白色背景,鼠标 hover 时变浅灰
  • 选中座位(可选扩展):蓝色背景区分

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 08:36:22