LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

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

admin
2025年12月14日 17:1 本文热度 832
在现代在线票务系统中,可视化选座功能是提升用户体验的重要组成部分。用户可以在购票过程中直观地查看座位布局,选择心仪的座位,这种交互方式大大提高了用户的参与感和满意度。本文将详细介绍如何使用 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座等不同类型座位并设置不同价格

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

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

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

完整代码

git地址:https://gitee.com/ironpro/hjdemo/blob/master/seat-select/index.html
<!DOCTYPE html><html lang="zh-CN"><head>  <meta charset="UTF-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>影院选座</title>  <style>      * {          margin0;          padding0;          box-sizing: border-box;      }
      body {          background#f5f5f5;      }
      .container {          max-width750px;          margin0 auto;          padding20px;      }
      .screen {          text-align: center;          margin20px 0;          color#666;      }
      .seat-map {          display: grid;          gap10px;          justify-content: center;          background: white;          padding20px;          border-radius10px;          box-shadow0 2px 10px rgba(0,0,0,0.1);      }
      .seat-row {          display: flex;          gap10px;          align-items: center;      }
      .seat {          width30px;          height30px;          border-radius4px;          display: flex;          align-items: center;          justify-content: center;          font-size14px;          cursor: pointer;          transition: all 0.2s;      }
      .status-color.available.seat.available {          background#e0e0e0;          color#666;      }
      .status-color.selected.seat.selected {          background#03fb81;          color: white;      }
      .status-color.sold.seat.sold {          background#ff4d4f;          color: white;          cursor: not-allowed;      }
      .status {          display: flex;          gap20px;          justify-content: center;          margin20px 0;      }
      .status-item {          display: flex;          align-items: center;          gap5px;      }
      .status-color {          width20px;          height20px;          border-radius3px;      }      .selected-info {          background: white;          padding20px;          border-radius10px;          box-shadow0 2px 10px rgba(0,0,0,0.1);          max-width750px;          margin0 auto;      }      #selected-seats {          display: grid;          grid-template-columnsrepeat(auto-fill, minmax(100px1fr));          gap10px;      }
      .selected-seat-item {          background-color#f0f0f0;          border-radius6px;          padding8px;          text-align: center;          font-size14px;          color#333;          display: flex;          flex-direction: column;          justify-content: center;          align-items: center;      }      .btn {          max-width750px;          margin20px auto;          padding14px;          text-align: center;          background-color#30c501;          color: white;          font-weight: bold;          border-radius6px;          cursor: pointer;          transition: background-color 0.2s ease;      }
      .btn:hover {          background-color#02d66d;      }
      .btn:disabled {          background-color#ccc;          cursor: not-allowed;      }  </style></head><body><div class="container">  <div class="screen">银幕</div>  <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>  <div>    <div class="btn" id="btn">请先选座</div>  </div></div>
<script>  // 单价  const pricePerSeat = 45;  // 生成座位数据  const seatData = [    [11101111],    [11111111],    [11110111],    [11111111],    [11111111],    [11111111],  ];
  const seatMapElem = document.getElementById('seat-map');
  // 座位点击事件  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();  });
  // 初始化座位图  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);    });  }
  // 更新选座信息  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})` : '请先选座';  }
  // 初始化  initSeatMap();</script></body></html>


阅读原文:原文链接


该文章在 2025/12/15 9:09:36 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved