使用 HTML + JavaScript 实现影院选座系统(附完整代码)


在现代在线票务系统中,可视化选座功能是提升用户体验的重要组成部分。用户可以在购票过程中直观地查看座位布局,选择心仪的座位,这种交互方式大大提高了用户的参与感和满意度。本文将详细介绍如何使用 HTML、CSS 和 JavaScript 构建一个影院选座系统。

效果演示

本系统实现了典型的影院选座界面。用户可以通过点击座位来选择或取消选择,系统会实时更新选座信息和总价。

页面结构

页面从上到下主要包括以下几个功能区域:座位展示区(seat-map)、状态说明区(status)、选座信息区(selected-info)。

座位展示区

座位展示区位于页面中央,采用网格布局展示所有座位。每个座位用一个小方块表示,不同颜色代表不同状态(可选、已选、已售)。

<div class="seat-map" id="seat-map"></div>


状态说明区

状态说明区展示了座位的不同状态及其对应的颜色标识,帮助用户快速识别座位状态。

<div class="status">
  <div class="status-item">
    <div class="status-color available"></div>
    <span>可选</span>
  </div>
  <div class="status-item">
    <div class="status-color selected"></div>
    <span>已选</span>
  </div>
  <div class="status-item">
    <div class="status-color sold"></div>
    <span>已售</span>
  </div>
</div>

选座信息区

选座信息区展示用户已经选择的座位信息及总价格,实时更新选座状态。

<div class="selected-info">
  <div id="selected-seats">暂未选座</div>
</div>

核心功能实现

数据结构设计

系统使用二维数组 seatData 来表示座位布局,其中1表示可选座位,0表示已售座位。

const seatData = [
  [1, 1, 1, 0, 1, 1, 1, 1],
  [1, 1, 1, 1, 1, 1, 1, 1],
  [1, 1, 1, 1, 0, 1, 1, 1],
  [1, 1, 1, 1, 1, 1, 1, 1],
  [1, 1, 1, 1, 1, 1, 1, 1],
  [1, 1, 1, 1, 1, 1, 1, 1],
];

座位初始化

initSeatMap 函数负责根据座位数据生成可视化的座位布局。该函数遍历座位数据,为每个座位创建DOM元素,并根据座位状态设置相应的CSS类和数据属性。

function initSeatMap() {
  seatData.forEach((row, rowIndex) => {
    const rowDiv = document.createElement('div');
    rowDiv.className = 'seat-row';
    // 添加座位
    for (let i = 0; i < row.length; i++) {
      const seat = document.createElement('div');
      seat.className = row[i] === 0 ? 'seat sold' : 'seat available';
      seat.textContent = i+1;
      seat.dataset.row = rowIndex + 1;
      seat.dataset.number = i+1;
      seat.dataset.status = row[i];
      rowDiv.appendChild(seat);
    }
    seatMapElem.appendChild(rowDiv);
  });
}

选座交互处理

通过事件委托机制处理座位点击事件,实现座位状态切换。当用户点击座位时,系统会检查座位是否可选,如果是则切换其状态,并更新选座信息。

seatMapElem.addEventListener('click', (e) => {
  const seat = e.target.closest('.seat');
  if (!seat || seat.classList.contains('sold')) return;

  const currentStatus = seat.dataset.status;
  if (currentStatus === '1') { // 可选
    seat.classList.remove('available');
    seat.classList.add('selected');
    seat.dataset.status = '2';
  } else { // 已选
    seat.classList.remove('selected');
    seat.classList.add('available');
    seat.dataset.status = '1';
  }
  updateSelectedInfo();
});

选座信息更新

updateSelectedInfo 函数负责更新已选座位信息和总价显示。每当座位状态发生变化时,此函数会重新收集所有已选座位信息,更新显示内容和总价。

function updateSelectedInfo() {
  const selected = document.querySelectorAll('#seat-map .selected');
  const seatsList = Array.from(selected).map(seat => ({
    row: seat.dataset.row,
    number: seat.dataset.number
  }));

  // 动态更新座位信息容器
  const selectedSeatsElem = document.getElementById('selected-seats');
  selectedSeatsElem.innerHTML = ''; // 清空当前内容

  if (seatsList.length === 0) {
    selectedSeatsElem.textContent = '暂未选座';
  } else {
    seatsList.forEach(seat => {
      const seatDiv = document.createElement('div');
      seatDiv.className = 'selected-seat-item';
      seatDiv.innerHTML = `<span>${seat.row}排${seat.number}座</span>
                <span>¥${pricePerSeat}</span>
            `;
      selectedSeatsElem.appendChild(seatDiv);
    });
  }

  // 更新总价和按钮文字
  const totalPrice = selected.length * pricePerSeat;
  const btnElem = document.getElementById('btn');
  btnElem.textContent = selected.length > 0 ? `确认选座 (¥${totalPrice})` : '请先选座';
}

扩展建议

座位锁定机制:增加座位锁定功能,防止多个用户同时选择同一座位

最佳座位推荐:根据观影体验推荐最佳座位区域

情侣座/家庭座:支持连续座位的选择限制

座位类型区分:区分普通座、VIP座等不同类型座位并设置不同价格

场次选择:支持不同时段场次的座位状态管理

座位图自定义:允许管理员自定义座位布局和区域划分

座位预订倒计时:为已选座位添加保留时间限制

0 条评论

当前评论已经关闭


登录用户头像
  • 从业日期: 2014/03/20
  • 性别:
口头禅

每天搬一点,幸福多一点

62

发帖数

98

源码数

0

接单

2

获赞

13

获评

源码信息
  • 积分优惠充值通道: 点我传送
  • 源码编号: NO0000445
  • 下载方式: 免费
  • 源码类型: 静态页面源码