影院座位选择简易实现(uniapp)

界面展示

主要使用到uniap中的movable-area,和movable-view组件实现。

代码逻辑分析

1、使用movable-area和movea-view组件,用于座位展示

<div class="ui-seat__box">
	<movable-area  class="ui-movableArea">
		<movable-view></movable-view>
	</movable-area>
</div>
.ui-movableArea {
		width: 600rpx;
		height: 500rpx;
		border: 1rpx solid #999;
		overflow: hidden;
	}

先给movable-area组件定义宽高,用于展示区域

2、 给moveable-view设置可移动,宽高等

<movable-area class="ui-movableArea">
				<movable-view direction="all" :out-of-bounds="false" :scale="false" class="ui-movableView"
					:style="{width:60 * whData.width + 'px',height:40 * whData.height + 'px'}" @change="handleMove"
					scale-max="1.5"
					damping="200"
					@scale="handleSize">

				</movable-view>
			</movable-area>

其中direction,out-of-bounds,scale,scale-max,damping,@scale等配置项在uniapp文档中查看介绍,分别表示为(是否全方向移动,超出能否移动,能否放大,最大的放大倍数,回弹时间,移动的回调)

3、影院的座位数据

通过以下方法,随机生成id唯一的座位,用于座位展示

function generateSeatArray(count) {
  const seats = [];
  for (let i = 0; i < count; i++) {
    seats.push({
      id: i + 1, // 随机生成 1 到 100 之间的唯一ID
      seat_x: (i % 11) + 1, // 规律递增 seat_x,范围 1 到 11
      seat_y: Math.floor(i / 11) + 1, // 规律递增 seat_y,范围 1 到 11
      canBuy: Math.random() > 0.5, // 随机生成 true 或 false
      price: Math.floor(Math.random() * 81) + 20 // 随机生成 20 到 100 之间的整数
    });
  }
  return seats;
}
export default generateSeatArray;

此方法结果为对象数组,表示以左上角为原点,右边为x轴正方向,下面为y轴正方向的坐标(seat_x,seat_y),canBuy表示能否购买此座位,price表示座位价格

[
    {
		seat_x: 1,
		seat_y: 1,
		canBuy: true,
		price: 20
	},
    {
		seat_x: 2,
		seat_y: 1,
		canBuy: true,
		price: 20
	},
    ........
]

4、moveable-view的宽高设置

回到标题2的代码片段

<movable-area class="ui-movableArea">
				<movable-view direction="all" :out-of-bounds="false" :scale="false" class="ui-movableView"
					:style="{width:60 * whData.width + 'px',height:40 * whData.height + 'px'}" @change="handleMove"
					scale-max="1.5"
					damping="200"
					@scale="handleSize">

				</movable-view>
			</movable-area>

在mova-view中有 :style="{width:60 * whData.width + 'px',height:40 * whData.height + 'px'}"

whData的数据如下所示,拿到座位数据作为参数传给handleMax方法,得到最大的宽和高

handleMax(array) {
				const maxData = array.reduce((preObj, cur) => {
					preObj.width = Math.max(preObj.width, cur.seat_x);
					preObj.height = Math.max(preObj.height, cur.seat_y)
					return preObj;
				}, {
					width: 0,
					height: 0
				})
				return maxData;
			},

 datalist是标题3中生成的座位数据

this.whData = this.handleMax(dataList);
whData = {
 widht:10,
 height:10
}

5、座位展示

<movable-area class="ui-movableArea">
				<movable-view direction="all" :out-of-bounds="false" :scale="false" class="ui-movableView"
					:style="{width:60 * whData.width + 'px',height:40 * whData.height + 'px'}" @change="handleMove"
					scale-max="1.5"
					damping="200"
					@scale="handleSize">
                    <view class="ui-seat">
						<!-- 座位 -->
						<view class="ui-item" v-for="item in seatList" :key="item.id"
							:style="{top:30 * item.seat_y + 'px',left:50 * item.seat_x + 'px'}"
							@click="handleSelect(item)">
							<view class="ui-item__class__can" v-if="item.canBuy">{{item.seat_x}},{{item.seat_y}}</view>
							<view class="ui-item__class" v-else>{{item.seat_x}},{{item.seat_y}}</view>
						</view>
					</view>
				</movable-view>
			</movable-area>

在moveabel-view中新增view组件,用于展示每一个座位 ,注意看类(ui-seat)设置成相对定位

	.ui-seat {
		display: flex;
		flex-wrap: wrap;
		position: relative;
	}

类(ui-item)设置成绝对定位


	.ui-item {
		margin: 5px;
		border: #999 1px solid;
		/* padding: 20rpx; */
		position: absolute;
	}

 因为在现实情况下会出现某个地方没有座位的情况,需要使用绝对定位的方式,根据每个座位的x,y的坐标进行展示

:style="{top:30 * item.seat_y + 'px',left:50 * item.seat_x + 'px'}"

这行表示根据每个item项的坐标进行对应展示,并且不会重叠

<view class="ui-item__class__can" v-if="item.canBuy">{{item.seat_x}},{{item.seat_y}}</view>

 <view class="ui-item__class" v-else>{{item.seat_x}},{{item.seat_y}}</view></view>

关于能否选择座位使用v-if来进行判断

6、左边列表展示 

			<movable-area class="ui-movableArea">
				<movable-view direction="all" :out-of-bounds="false" :scale="false" class="ui-movableView"
					:style="{width:60 * whData.width + 'px',height:40 * whData.height + 'px'}" @change="handleMove"
					scale-max="1.5"
					damping="200"
					@scale="handleSize">
					<view class="ui-seat">
						<!-- 座位 -->
						<view class="ui-item" v-for="item in seatList" :key="item.id"
							:style="{top:30 * item.seat_y + 'px',left:50 * item.seat_x + 'px'}"
							@click="handleSelect(item)">
							<view class="ui-item__class__can" v-if="item.canBuy">{{item.seat_x}},{{item.seat_y}}</view>
							<view class="ui-item__class" v-else>{{item.seat_x}},{{item.seat_y}}</view>
						</view>
						<!-- 列表 -->
						<view class="ui-list" :style="{left: moveX + 'px'}">
							<view class="ui-list__item" v-for="i in whData.height" :key="index">
								{{i + 1}}
							</view>
						</view>
					</view>
				</movable-view>

在座位代码下面新增列表展示,在moveable-view中有@change方法,用于获取上下左右移动了多少,并存到moveX,和moveY中,根据左移的距离判断列表位置

handleMove(e) {
				const {
					x,
					y,
					source
				} = e.detail;
				setTimeout(() => {
					this.moveX = Math.abs(x);
					this.moveY = y;
				}, 200)
			},

完整代码

<template>
	<view class="content">
		<view class="ui-top">
			电影信息
		</view>
		<view class="ui-body">
			以下是座位控制
		</view>
		<div class="ui-seat__box">
			<movable-area class="ui-movableArea">
				<movable-view direction="all" :out-of-bounds="false" :scale="true" class="ui-movableView"
					:style="{width:60 * whData.width + 'px',height:40 * whData.height + 'px'}" @change="handleMove"
					scale-max="1.5"
					damping="200"
					@scale="handleSize">
					<view class="ui-seat">
						<!-- 座位 -->
						<view class="ui-item" v-for="item in seatList" :key="item.id"
							:style="{top:30 * item.seat_y + 'px',left:50 * item.seat_x + 'px'}"
							@click="handleSelect(item)">
							<view class="ui-item__class__can" v-if="item.canBuy">{{item.seat_x}},{{item.seat_y}}</view>
							<view class="ui-item__class" v-else>{{item.seat_x}},{{item.seat_y}}</view>
						</view>
						<!-- 列表 -->
						<view class="ui-list" :style="{left: moveX + 'px'}">
							<view class="ui-list__item" v-for="i in whData.height" :key="index">
								{{i + 1}}
							</view>
						</view>
					</view>
				</movable-view>
			</movable-area>
		</div>

	</view>
</template>

<script>
	import seatfun from './seat-data.js';
	export default {
		data() {
			return {
				title: 'Hello',
				seatList: [],
				whData: {},
				moveX: 0,
				moveY: 0
			}
		},
		onLoad() {
			const dataList = seatfun(50);
			// dataList.splice(2,4);
			// dataList.splice(10,12);
			this.seatList = dataList;
			// 获取宽度
			this.whData = this.handleMax(dataList);
		},
		methods: {
			handleMax(array) {
				const maxData = array.reduce((preObj, cur) => {
					preObj.width = Math.max(preObj.width, cur.seat_x);
					preObj.height = Math.max(preObj.height, cur.seat_y)
					return preObj;
				}, {
					width: 0,
					height: 0
				})
				return maxData;
			},
			handleSelect(item) {
				// console.log(item.seat_x,item.seat_y);
				if (item.canBuy) {
					item.canBuy = !item.canBuy;
				} else {
					// console.log(item);
					uni.showToast({
						title: '此座位不可选'
					})
				}
			},
			handleMove(e) {
				const {
					x,
					y,
					source
				} = e.detail;
				setTimeout(() => {
					this.moveX = Math.abs(x);
					this.moveY = y;
				}, 200)
			},
			handleSize(e){
				const {x,y,scale} = e.detail;
				setTimeout(() => {
					this.moveX = Math.abs(x);
					this.moveY = y;
				}, 200)
			}
		}
	}
</script>

<style scoped>
	view {
		box-sizing: border-box;
	}

	.ui-top {
		height: 200rpx;
		background-color: greenyellow;
	}

	.ui-movableArea {
		width: 600rpx;
		height: 500rpx;
		border: 1rpx solid #999;
		overflow: hidden;
	}

	.ui-seat__box {
		display: flex;
		justify-content: center;
	}

	.ui-seat {
		display: flex;
		flex-wrap: wrap;
		position: relative;
	}

	.ui-movableView {
		width: 700rpx;
		height: 700rpx;
		overflow: hidden;
		background-color: antiquewhite;
	}

	.ui-item__class__can {
		width: 60rpx;
		height: 40rpx;
		background-color: darkred;
	}

	.ui-item__class {
		width: 60rpx;
		height: 40rpx;
		background-color: palegreen;
	}

	.ui-item {
		margin: 5px;
		border: #999 1px solid;
		/* padding: 20rpx; */
		position: absolute;
	}

	.active {
		background-color: greenyellow;
	}

	.ui-list {
		position: absolute;
		top: 30px;
		width: 50rpx;
		background-color: #fff;
	}

	.ui-list__item {
		margin: 10rpx;
		padding: 5rpx;
	}
</style>

seat-data.js代码

function generateSeatArray(count) {
  const seats = [];
  for (let i = 0; i < count; i++) {
    seats.push({
      id: i + 1, // 随机生成 1 到 100 之间的唯一ID
      seat_x: (i % 11) + 1, // 规律递增 seat_x,范围 1 到 11
      seat_y: Math.floor(i / 11) + 1, // 规律递增 seat_y,范围 1 到 11
      canBuy: Math.random() > 0.5, // 随机生成 true 或 false
      price: Math.floor(Math.random() * 81) + 20 // 随机生成 20 到 100 之间的整数
    });
  }
  return seats;
}
export default generateSeatArray;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/520948.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【QT学习】5.控件

一。控件的了解 1.控件作用 拖拽页面&#xff0c;所见即所得。 2.创建控件 3.向qt项目中添加资源 3.1显示图片 项目右键--》add new 创建结果&#xff1a; 添加资源到文件中 补充&#xff1a;使用代码的方式添加图片 3.2显示动图 1.添加动图资源 添加资源 2.显示动图 3.3显示…

基于单片机电子硬币储存器的设计

**单片机设计介绍&#xff0c;基于单片机电子硬币储存器的设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机电子硬币储存器的设计概要主要涵盖了硬件设计、软件设计、硬币识别、计数与储存等核心功能。以下是对该设…

OWASP TOP10 漏洞详解

前言 该内容是 OWASP TOP 10 的学习笔记&#xff0c;笔记内容来源 B 站龙哥的视频【12.Top漏洞10&#xff1a;服务器请求伪造_哔哩哔哩_bilibili】 一、访问控制崩溃 概念 未对通过身份验证的用户实施恰当的访问控制。攻击者可以利用这些缺陷访问未经授权的功能或数据&#xf…

【Linux】环境基础开发工具使用——gcc/g++使用

Linux编译器-gcc/g使用 1. 背景知识 1. 预处理&#xff08;进行宏替换 ) 2. 编译&#xff08;生成汇编 ) 3. 汇编&#xff08;生成机器可识别代码&#xff09; 4. 连接&#xff08;生成可执行文件或库文件 ) 2. gcc如何完成 格式 gcc [ 选项 ] 要编译的文件 [ 选…

阿德勒、荣格、埃里克森、霍妮、弗洛姆、沙利文的新精神分析理论

新精神分析理论&#xff0c;强调自我的自主性及其整合与调节功能&#xff0c;强调文化和社会因素对人格的重大影响。 一、阿德勒的个体心理学 阿德勒&#xff0c;是一个男人努力克服自卑感的优秀样板。阿德勒写了《超越与自卑》。 阿德勒&#xff0c;向意识层面扩展精神分析…

c++11的重要特性3

目录 1、lambda表达式 C98中的一个例子 lambda表达式的 lambda表达式语法 函数对象与lambda表达式 3、可变参数模板 递归获取 逗号表达式展开参数包 2、包装器 function包装器 bind 1、lambda表达式 C98中的一个例子 在C98中&#xff0c;如果想要对一个数据集合中的元素进…

NetSuite 自定义记录类型的权限控制

在近期的一个定制项目中&#xff0c;遭受了一次用户洗礼。有个好奇宝宝把我们的一个自定义类型的表记录进行了删除&#xff0c;导致一个重要功能失败。算是给我们扎实上了一课。自定义类型的权限也需要重视起来。所以&#xff0c;今朝我们记录下这个设置&#xff0c;同时写给未…

C++ setw() 函数

C setw() 函数 分类 编程技术 C setw() 函数用于设置字段的宽度&#xff0c;语法格式如下&#xff1a; setw(n) n 表示宽度&#xff0c;用数字表示。 setw() 函数只对紧接着的输出产生作用。 当后面紧跟着的输出字段长度小于 n 的时候&#xff0c;在该字段前面用空格补齐&…

《QT实用小工具·十五》多种样式的开关控件

1、概述 源码放在文章末尾 目前实现了三种样式的开关控件按钮&#xff0c;如下所示&#xff1a; 项目部分代码如下所示&#xff1a; #ifndef IMAGESWITCH_H #define IMAGESWITCH_H/*** 图片开关控件 * 1. 自带三种开关按钮样式。* 2. 可自定义开关图片。*/#include <QWid…

SpringBoot新增员工模块开发

需求分析与设计 一&#xff1a;产品原型 一般在做需求分析时&#xff0c;往往都是对照着产品原型进行分析&#xff0c;因为产品原型比较直观&#xff0c;便于我们理解业务。 后台系统中可以管理员工信息&#xff0c;通过新增员工来添加后台系统用户。 新增员工原型&#xf…

Vue中如何使用Tailwind CSS样式?多次引用不成功?具体步骤怎么做?

一、安装Tailwind CSS和依赖 在你的Vue项目中安装Tailwind CSS及其依赖。你可以使用npm或yarn来安装。 npm install tailwindcsslatest postcsslatest autoprefixerlatest # 或者yarn add tailwindcsslatest postcsslatest autoprefixerlatest 二、初始化Tailwind CSS np…

Linux常用命令-网络管理

文章目录 ping基本用法主要选项常见用途和理解输出注意事项 ifconfig基本用法配置网络接口示例高级功能 netstat基本用法常用选项示例注意事项 wget主要特点基本用法常见选项 示例注意事项 curl主要特点基本用法常见选项 示例注意事项 参考资料在线文档和手册图书在线教程和指南…

YOLO-World:实时开放词汇对象检测(论文+代码)

目录 一、YOLO-World摘要以及主要贡献 1.1摘要 1.2主要贡献 二、YOLO-World模型创新点总结 2.1YOLO Detector 2.2Text Encoder 2.3Re-parameterizable Vision-Language PAN 2.4核心创新点总结 三、如何应用 3.1推理预测 3.2自定义词汇推理 3.3自定义词汇类别…

Struts2的入门:新建项目——》导入jar包——》jsp,action,struts.xml,web.xml——》在项目运行

文章目录 配置环境tomcat 新建项目导入jar包新建jsp界面新建action类新建struts.xml,用来配置action文件配置Struts2的核心过滤器&#xff1a;web.xml 启动测试给一个返回界面在struts.xml中配置以实现页面的跳转&#xff1a;result再写个success.jsp最后在项目运行 配置环境 …

C++从入门到精通——类的定义及类的访问限定符和封装

类的定义及类的访问限定符和封装 前言一、类的定义类的两种定义方式成员变量命名规则的建议示例 二、类的访问限定符和封装访问限定符访问限定符说明C为什么要出现访问限定符例题 封装例题 前言 类的定义是面向对象编程中的基本概念&#xff0c;它描述了一类具有相同属性和方法…

Atlas 200 DK开发者套件的网络连接

一、参考资料 Atlas 200 DK官方文档 二、常用操作 1. Micro SD制卡 在windows系统上&#xff0c;一键制卡的步骤与Atlas 200I DK类似&#xff0c;但步骤更简单&#xff0c;详细步骤请参考&#xff1a;Windows系统制卡 2. Atlas 200 DK与PC机通信 2.1 准备工作 准备一根安…

一些好玩的东西

这里写目录标题 递归1.递归打印数组和链表?代码实现原理讲解二叉树的 前 中 后 序位置 参考文章 递归 1.递归打印数组和链表? 平常我们打印数组和链表都是 迭代 就好了今天学到一个新思路–>不仅可以轻松正着打印数组和链表 , 还能轻松倒着打印(用的是二叉树的前中后序遍…

vue事件代理

数据代理 Object.defineProperty 常见属性值 get和set函数 理解数据代理 Vue中的数据代理 Vue中的数据代理小结 事件处理 v-bind 事件处理小结 数据代理 Object.defineProperty 常见属性值 <body> <script type"text/javascript"> let person{n…

C++:逻辑运算符-非与或(19)

!非!a如果a为假&#xff0c;那么当前他就是真&#xff0c;如果a是真&#xff0c;那么他直接就是假&&与a&&ba与b都为真&#xff0c;那么就是真&#xff0c;如果两个里面有一个为假那么就是假||或a||ba或b有一个为真&#xff0c;那么就是真 非&#xff08;!&…

(学习日记)2024.03.31:UCOSIII第二十八节:消息队列常用函数

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…