微信小程序组件开发——可视化电影选座
点击上方 前端瓶子君,关注公众号
回复算法,加入前端编程面试算法每日一题群
一. 简介
想必很多人都有陪男女朋友去看电影的经历吧,是不是在每次选座的时候你都要征求女盆友或男盆友的意见,什么?不征求?!那你完了!
目前市场上许多的电影购票app和小程序中,为了让观众老爷们在线上更好地选择自己心怡的位置,方便可视化的选座数据必不可少,在此, 让我们一起来看看这个好用的可视化选座组件吧!
视图效果如下:
如果各位看官老爷感兴趣的话,请继续往下看!
1. 组件数据
首先呢,我们需要给该组件传入两个数据,以便显示组件时使用,一个是电影厅的厅号,一个就是座位的数组,如下:
厅号:大写数字字符串
座位数据:数组点阵,左右的空白用0表示,普通座位用1表示,优选座位用2表示,已经被其他观众选择的座位用3表示,初始数据如下:
组件的 js文件中需声明传过来的数据,与页面声明方式不同,组件的properties中声明数据需要写出数据类型。
properties: {
seatings: Array,
hallNumber: String
},
复制代码
2. 组件页面布局
页面中有能动的,也有不能动的,当然还有自己能动的;这个组件呢,顶部的标识区属于静态部分和座位区是可移动的并且可以双指缩放,具体结构如下:
1. 标识区构成
这个区域主要是起提示作用,提示座位的信息,包括了普通区和优选区,当然,代码直接可以偷取座位区域中的座位的WXSS样式,用signs_normal和seat_Excellent类名实现。当然,谁不喜欢c位呢~
<view class="signs_normal">
<view class="seatNormal"></view> <text>普通区</text>
</view>
<view class="signs_excellent">
<view class="seatExcellent"></view> <text>优选区</text>
</view>
</view>
复制代码
座位区构成
这个部分我们分为了三个小部分:屏幕,电影厅介绍和座位区, 听我细细道来!
2.1 电影屏幕:
为实现荧幕弧形效果,俺们可以通过遮盖法实现,非常好用! 先通过长方形盒子构建荧幕长宽,再用一个椭圆形大饼的边缘显示在长方形盒子里,其他部分用overflow: hidden属性遮盖,再调整背景颜色和边框颜色即可实现荧幕效果
html如下:
<view class="visual_screen">
<view class="screen"></view>
</view>
复制代码
wxss如下:
.visual_screen {
height: 30rpx;
width: 100%;
display: flex;
justify-content: center;
overflow: hidden;
margin-bottom: 10rpx;
}
.screen {
margin-top: 0;
padding: 0;
height: 30vw;
width: 100vw;
box-sizing: border-box;
border: 15rpx solid #c9cdd3;
border-radius: 50%;
}
复制代码
2.2 电影厅介绍:
这部分相对来说较为简单,直接插入传输过来的数据,微调样式即可
wxml:
<view class="visual_title">{{hallNumber}}号厅-(请佩戴口罩、1.3米以上儿童购票)</view>
wxss:
.visual_title {
font-size: 23rpx;
width: 100%;
height: 20rpx;
text-align: center;
color: #6d6d6d;
margin-bottom: 30rpx;
}
复制代码
2.3 座位区域:
基础结构:
基础单位 :由于设定座位的宽度为基本单位vw,便于统一单位和机型配适,所以我这里将高度也以vw为单位进行设计
座位样式 : 我们通过之前传输过来的座位数组可知,我们的座位形式有五种,分别是:seatNormal(普通座位)、seatExcellent(优选座位)、seatNone(空白座位)、seatChosen(不可选座位)和selected(当前已选座位),这里座位的基础样式是一样的可以统一,再单独写各自独特的样式。其中空白座位只要设置边框颜色为透明就可以达到效果。
.seatNormal, .seatExcellent, .seatNone, .seatChosen {
height: 4vw;
width: 4vw;
margin: 1vw;
border-radius: 8rpx;
box-sizing: border-box;
}
.seatNormal {
border: 1rpx solid #63c0c0;
}
.seatChosen {
border: 1rpx solid red;
background-color: red;
}
.selected {
border: 1rpx solid #05ca90;
background-color: #05ca90;
}
.seatExcellent {
border: 1rpx solid #f18e14;
}
.seatNone {
border: 1rpx solid rgba(0, 0, 0, 0);
}
复制代码
推荐 好用的样式:在wxss中我们用到了一个非常好用的样式 “box-sizing: border-box;”,这个样式为元素设定的宽度和高度决定了元素的边框盒。就是说,为元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制,通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度,便于控制元素大小。
**总体布局** :座位区域使用的是弹性布局display:flex,并使用flex-wrap: wrap,让座位填满后自动换行,大盒子包住一个盒子,让里面的盒子弹性居中,达到整体居中的效果。
.visual_seatings {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 43vw;
}
.visual_seating {
width: 90%;
height: 43vw;
display: flex;
flex-wrap: wrap;
}
复制代码
可移动可缩放区域: 由于方便座位选择,我们设定座位区域可移动,并可通过双指缩放的,所以我们需要用到微信小程序的一个API:movable-area[1]和 movable-view[2]。
movable-area: 这个区域必须设置width和height属性,不设置则默认为10px,同时,当movable-view小于movable-area时,movable-view的移动范围是在movable-area内, 当movable-view大于movable-area时,movable-view的移动范围必须包含movable-area(x轴方向和y轴方向分开考虑)。
movable-view: 标签属性设定移动方向全方位direction="all";支持双指缩放scale="{{true}}";最大最小缩放倍数scale-min="0.3"和scale-max="1.5";如果想绑定触发条件还可以添加绑定方法,拖动绑定事件:bindchange,缩放绑定事件bindscale等等
little tips: 由于movable-view区域在放大时, 所处的x, y坐标不变会导致view区域会超出area区域. 为了view可移动区域不遮挡上方元素, 所以可采取减少放大倍数上限并可在上方添加一些空白区域, 增加页面美观性.
详细用法参考微信小程序官网手册: developers.weixin.qq.com/miniprogram…[3]
3. 组件业务逻辑
座位数据输出 : 上回说到,座位数据是由数组存储的,里面不同的座位用不同的数字表现, 所以我们在输出数据时需要作判断. 这里通过block标签对数组数据循环输出, 然后判断数组数据, 输出不同的格式.
选择座位 : 要做到在用户点击某个座位时, 那个座位样式改变并记录座位数据.
首先, 需要传输在循环时的下标数据wx:for="{{seatings}}" wx:key="Index" data-index="index", 每个座位的view中绑定selected事件, 在js文件selected方法中收到下标数据;我们需要用到已选择座位的总数(限制为六个)和下标数组(储存已点击的座位)两个数据, 所以我们在data中声明selectedIndex: [ ], selectedNum: 0, methods方法中声明方法;
selected方法逻辑 : 先保存下标index, 判断下标数组中是否存在该元素(使用数组的indexOf()方法), 若存在,则表明之前已选择现在再次点击取消, 需删除将改下标从下标数组在删除,总已选择座位数减一 ; 否则不存在则判断已选择总数是否小于6,小于则将该数据插入数组中, 总已选择座位数加一, 不小于提示最多选择六张票;
这个时候,我们就有了下表数据啦,就可进行更多更复杂的业务操作啦!!
tip : 由于数组没有移除某个元素的方法 , 所以另外声明remove()方法, 先获取元素下标再删除.
selected(e) {
let index = e.currentTarget.dataset.index;
if(this.data.selectedIndex.indexOf(index) != -1){
let selectedIndex = this.remove(this.data.selectedIndex, index);
let selectedNum = this.data.selectedNum - 1;
this.setData({
selectedIndex,
selectedNum
})
}else{
if(this.data.selectedNum < 6){
let selectedNum = this.data.selectedNum + 1;
let selectedIndex = this.data.selectedIndex.concat(index);
this.setData({
selectedIndex,
selectedNum
})
}else{
wx.showToast({
title: '最多选择六张票',
})
}
}
},
remove(arr, ele) {
var index = arr.indexOf(ele);
if (index > -1) {
arr.splice(index, 1);
}
return arr;
}
复制代码
已选样式改变 : 在座位view中, 我们用到了三元运算符进行数据判断: class="{{tools.indexOf(selectedIndex, index)?'selected': ''}}"
若前面的结果为true即数组中存在这个数据的下标, 则添加selected类名, 座位样式改变; 否则添加空类名.tips : 由于数组的indexOf方法在wxml中失效, 所以我们需要在pages同级目录下util文件夹中声明一个indexOf函数供三元运算调用,自己动手丰衣足食!使用时只需通过 wxs src="../../util/indexof.wxs" module="tools" 进行声明, 就可使用 tools.indexOf 方法,效果和数组自带的indexOf方法是一样一样的~
// indexOf方法
function indexOf(arr, value) {
if (arr.indexOf(value) < 0) {
return false;
} else {
return true;
}
}
module.exports.indexOf = indexOf;
复制代码
具体组件源码如有需要的话,请在gitee中获取哦!
gitee.com/jensmith/so…[4]
如果大家觉得这篇文章对大家有帮助的话 , 请多多支持该文章 , 多多点赞哦❤!!
关于本文
来源:Jusen_Fu
https://juejin.cn/post/6996913047725932575