在微信小程序实现选餐功能,用到template功能、animate动画库微信版(animate.wxss),效果图:



案例
页面:
- pages/menu/menu.wxml
<!-- SM ADD 引入模版-->
<import src="/template/detailAdd.wxml"/>
<import src="/template/detailview.wxml"/>
<!-- 使用模版 -->
<template is="detailAdd" data="{{isshowDetail, currentDetail}}"/>
<template is="detailView" data="{{isviewDetail, selectDetailList}}"/>
<!-- SM ADD 引入模版 end-->
<view class="detail">
<view class="content">
<view class="menu-container">
<scroll-view scroll-y="true" class="scroll-view" scroll-into-view="head-{{indexSize}}">
<view class="scroll-view-ul">
<block wx:for="{{detail}}" wx:for-item="item" wx:key="index" id="head-{{index}}">
<view class="scroll-view-item {{indexSize === index?'active':''}}" bindtap="scrollTo"
data-index="{{index}}">{{item.title}}
</view>
</block>
</view>
</scroll-view>
</view>
<swiper indicator-dots='true' class="detail-container" bindchange="change" data-index="{{index}}"
current="{{indexSize}}" indicator-dots="{{indicatorDots}}" autoplay="{{autoplay}}" duration="{{duration}}">
<swiper-item wx:for="{{detail}}" wx:for-item="item" wx:key="index">
<scroll-view scroll-y="true" class=" market-scroll-list">
<view class="title">{{detail[indexSize].title}} </view>
<a wx:for="{{detail[indexSize].list}}" wx:key="index" wx:key="index" item="item" key="key">
<view class="inner">
<view class="cover" data-item="{{item}}" data-pid="{{detail[indexSize].id}}" bindtap="detailAdd">
<image src="./add.png"></image>
</view>
<view class="info overflow">
<view class="info-title overflow">{{item.title}}</view>
</view>
<view class="num" data-item="{{item}}" data-pid="{{detail[indexSize].id}}" bindtap="goDetails">
<text class="text">详情</text>
</view>
</view>
</a>
</scroll-view>
</swiper-item>
</swiper>
</view>
<view class="footer" bindtap="selectDetails">
<view class="footer_left">已选择<text>{{selectDetailLen}}</text>菜品</view>
<view class="footer_right" catchtap="finishclick">结账</view>
</view>
</view>
- pages/menu/menu.js
Page({
/**
* 页面的初始数据
*/
data : {
indexSize: 0,
indicatorDots: false,
autoplay: false,
duration: 1, //可以控制动画
list: '',
detail: [
{
id: 1,
title: '今日热门',
list: [
{
id: '11',
title: '无骨鱼',
},
{
id: '12',
title: '海带',
},
{
id: '13',
title: '特色小炒',
},
{
id: '14',
title: '酱爆牛肉',
},
{
id: '15',
title: '宫保鸡丁',
},
{
id: '16',
title: '宫保鸡丁2',
},
{
id: '17',
title: '宫保鸡丁3',
},
{
id: '18',
title: '宫保鸡丁4',
},
{
id: '19',
title: '宫保鸡丁5',
},
{
id: '121',
title: '宫保鸡丁6',
},
{
id: '122',
title: '宫保鸡丁7',
},
{
id: '123',
title: '宫保鸡丁8',
},
{
id: '124',
title: '宫保鸡丁9',
},
{
id: '125',
title: '宫保鸡丁10',
},
{
id: '126',
title: '宫保鸡丁11',
},
{
id: '127',
title: '宫保鸡丁12',
},
{
id: '128',
title: '宫保鸡丁13',
},
{
id: '129',
title: '宫保鸡丁14',
},
{
id: '130',
title: '宫保鸡丁15',
},
{
id: '131',
title: '宫保鸡丁16',
},
{
id: '132',
title: '宫保鸡丁17',
},
{
id: '133',
title: '宫保鸡丁18',
},
{
id: '134',
title: '宫保鸡丁19',
},
],
},
{
id: 2,
title: '凉菜',
list: [
{
id: '21',
title: '海带',
},
{
id: '22',
title: '黄瓜',
},
{
id: '23',
title: '花生米',
},
{
id: '24',
title: '皮蛋',
},
{
id: '25',
title: '紫菜',
},
{
id: '26',
title: '拼盘',
},
],
},
{
id: 3,
title: '素菜',
list: [
{
id: '31',
title: '小青菜',
},
{
id: '32',
title: '上海青菜',
},
{
id: '33',
title: '白菜',
},
{
id: '34',
title: '土豆',
},
],
},
{
id: 4,
title: '荤菜',
list: [
{
id: '41',
title: '特色荤菜',
},
{
id: '42',
title: '肉丝',
},
{
id: '43',
title: '无骨鱼',
},
{
id: '44',
title: '鸡肉',
},
{
id: '45',
title: '牛肉',
},
{
id: '46',
title: '肉丁',
},
{
id: '47',
title: '酱爆牛肉',
},
{
id: '48',
title: '基围虾',
},
{
id: '49',
title: '宫保鸡丁',
},
{
id: '410',
title: '鸡公煲',
},
],
},
{
id: 5,
title: '特色菜',
list: [
{
id: '51',
title: '特色菜1',
},
{
id: '52',
title: '特色菜2',
},
{
id: '53',
title: '特色菜3',
},
{
id: '54',
title: '特色菜4',
},
{
id: '55',
title: '特色菜5',
},
{
id: '56',
title: '特色菜6',
},
{
id: '57',
title: '特色菜7',
},
],
},
{
id: 6,
title: '饮料',
list: [
{
id: '61',
title: '果汁',
},
{
id: '62',
title: '西瓜汁',
},
{
id: '63',
title: '酸梅汁',
},
{
id: '64',
title: '苹果汁',
},
{
id: '65',
title: '可乐',
},
{
id: '66',
title: '雪碧',
},
{
id: '67',
title: '矿泉水',
},
{
id: '68',
title: '哇哈哈',
},
{
id: '69',
title: '旺仔',
},
{
id: '610',
title: '牛奶',
},
],
},
{
id: 7,
title: '其它',
list: [
{
id: '71',
title: '其它1',
},
{
id: '72',
title: '其它2',
},
{
id: '73',
title: '其它3',
},
{
id: '74',
title: '其它4',
},
{
id: '75',
title: '其它4',
},
{
id: '76',
title: '其它5',
},
{
id: '77',
title: '其它5',
},
{
id: '78',
title: '其它6',
},
{
id: '79',
title: '其它7',
},
{
id: '710',
title: '其它8',
},
{
id: '711',
title: '其它8',
},
{
id: '712',
title: '其它9',
},
{
id: '713',
title: '其它10',
},
{
id: '714',
title: '其它11',
},
{
id: '715',
title: '其它12',
},
{
id: '716',
title: '其它13',
},
{
id: '717',
title: '其它14',
},
{
id: '718',
title: '其它15',
},
{
id: '719',
title: '其它16',
},
{
id: '720',
title: '其它17',
},
{
id: '721',
title: '其它18',
},
{
id: '722',
title: '其它19',
},
{
id: '723',
title: '其它20',
},
{
id: '724',
title: '其它21',
},
{
id: '725',
title: '其它22',
},
{
id: '726',
title: '其它23',
},
{
id: '727',
title: '其它24',
},
],
},
],
// SM ADD 已经选择的事项
selectDetailList: [],
// 是否显示添加事项
isshowDetail: false,
// 当前选中的事项记录
currentDetail: {},
selectDetailLen: 0,
// 详情显示
isviewDetail: false
},
// SM add 详情、添加等方法
// 去详情
goDetails(e){
let item = e.currentTarget.dataset.item;
let pid = e.currentTarget.dataset.pid;
console.log('去详情页面= ', item, pid);
},
// 添加事项
detailAdd(e){
let item = Object.assign({number:1, isTranslate: false}, e.currentTarget.dataset.item);
let pid = e.currentTarget.dataset.pid;
// 根据选择的检索出最新数据
let selectData = this.data.selectDetailList
// 循环查找 是否存在已有记录,
let index = selectData && selectData.find(citem => citem.id === item.id)
// 如果存在+1 并获取到当前记录赋值给 currentDetail
if(index && index.id){
item = index;
}
// 显示弹出框
this.setData({
isshowDetail: true,
currentDetail: item
})
},
// 查看选择的详情
selectDetails(e){
console.log('查看选择的详情');
let isviewDetail = !this.data.isviewDetail;
this.setData({
isviewDetail: isviewDetail
})
},
// 删除详情
xdetailviewdel(e){
//
console.log('删除');
let index = e.currentTarget.dataset.delindex;
console.log('删除的索引==', index);
let selectDetailList = this.data.selectDetailList;
//delete selectDetailList[index];
selectDetailList.splice(index, 1)
console.log('删除后最新记录:', selectDetailList);
this.setData({
selectDetailList: selectDetailList || [],
selectDetailLen: selectDetailList.length
})
if(selectDetailList.length == 0){
// 关闭
this.selectDetails();
}
},
// 清空事项
xdetailviewClean(e){
console.log('清空事项----');
this.setData({
selectDetailList: [],
selectDetailLen: 0
})
// 关闭
this.selectDetails();
},
// 弹出添加事项点击事件
xdetailok(e){
let item = this.data.currentDetail;
let selectData = this.data.selectDetailList;
// 获取最新数据,并更改
let index = selectData && selectData.findIndex(citem => citem.id === item.id)
if(index != -1){
selectData[index] = item
}else{
// 没找到
selectData.push(item);
}
// 还原当前记录标示
this.setData({
currentDetail: {},
selectDetailList: selectData,
selectDetailLen: selectData.length
})
console.log('最新记录:', selectData);
// 关闭
this.closeDetail();
},
// 关闭事项弹出框
xdetailClose(e){
this.closeDetail();
},
// 关闭事项框
closeDetail(){
this.setData({
isshowDetail: false
})
},
// 事项加减运算
xdetailCalc(e){
let type = e.currentTarget.dataset.calc;
let cdata = this.data.currentDetail;
if(type == 1){
if(cdata.number > 1){
let item = Object.assign(cdata, {number: cdata.number-1})
this.setData({
currentDetail: item
})
}
}else{
if(cdata.number < 99){
let item = Object.assign(cdata, {number: cdata.number+1})
this.setData({
currentDetail: item
})
}
}
},
// 是否翻译点击按钮
translatetap(e){
let isTranslate = e.currentTarget.dataset.transle;
let currentDetail = this.data.currentDetail;
let item = Object.assign(currentDetail, {isTranslate: JSON.parse(isTranslate)});
this.setData({
currentDetail: item
})
},
// SM add 详情、添加等方法 end
finishclick:function(){
let selectData = this.data.selectDetailList;
console.log('选择的事项记录-----', selectData)
},
change(e) {
this.setData({
indexSize: e.detail.current
})
},
scrollTo(e) {
this.setData({
indexSize: e.target.dataset.index
})
}
})
- pages/menu/menu.wxss
.overflow {
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
}
.content {
display: flex;
width: 100%;
position: absolute;
bottom: 0rpx;
left: 0;
top: 0;
overflow: hidden;
}
/* SM add 添加区域高度 begin */
.content {
height: -webkit-calc(100vh - 150rpx);
height: calc(100vh - 150rpx);
}
/* SM add 添加区域高度 end */
.menu-container {
width: 160rpx;
flex: 0 0 160rpx;
background: #f6f6f6;
}
.detail-container {
flex: 1;
height: 100%;
}
.scroll-view {
width: 100%;
height: 100%;
}
.scroll-view-ul {
width: 100%;
height: 100%;
background-color: #fff;
}
.scroll-view-item {
height: 110rpx;
width: 100%;
font-size: 28rpx;
color: #666;
border-left: 8rpx solid transparent;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.scroll-view-item:after {
content: '';
left: 0;
right: 0;
bottom: 0;
height: 1px;
background-color: #dfdfdf;
transform: scaleY(0.5);
position: absolute;
}
.active {
background: #F1F1F1;
border-left: 8rpx solid #39B54A;
}
.market-scroll-list {
height: 100%;
}
.title {
height: 70rpx;
line-height: 70rpx;
background-color: #f6f6f6;
border-left: 6rpx solid #39B54A;
padding-left: 30rpx;
}
.inner {
display: flex;
position: relative;
border-bottom: 1px solid #F1F1F1
}
.inner:after {
left: 30rpx;
right: 0;
bottom: 0;
/* height: 1px; */
background-color: #dfdfdf;
/* transform: scaleY(0.5); */
position: absolute;
}
.cover {
width: 45rpx;
height: 35rpx;
padding: 20rpx;
margin-top: 5rpx;
}
.cover image {
width: 100%;
height: 100%;
}
.info-title {
height: 80rpx;
line-height: 80rpx;
color: #AAAAAB;
font-size: 28rpx;
}
.info-desc {
color: #666666;
font-size: 22rpx;
margin-top: 5rpx;
}
.num {
width: 120rpx;
height: 80rpx;
line-height: 80rpx;
position: relative;
}
.text {
position: absolute;
bottom: 0;
font-size: 26rpx;
color: #009999;
}
/* 底部 */
.footer {
width: 100%;
height: 150rpx;
background-color: #e7e4e4;
position: absolute;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(244, 244, 244, 0.5);
border-top: 1px solid #DDDDDD;
}
.footer_left {
width: 300rpx;
height: 100rpx;
line-height: 100rpx;
margin-top: 25rpx;
float: left;
margin-left: 50rpx;
}
text{
color: red;
font-size: 40rpx;
}
.footer_right {
width: 200rpx;
height: 70rpx;
line-height: 70rpx;
border-radius: 50rpx;
text-align: center;
background-color: #fe6701;
float: right;
color: #fff;
font-size: 30rpx;
opacity: 1;
margin-top: 40rpx;
margin-right: 50rpx;
}
- pages/menu/menu.json
{
"navigationBarTitleText": "菜单选择"
}
template
- template/detailAdd.wxml
<!--
@author:SM
@desc:添加事项模版视图
fadeInUp 显示
fadeOutDown 隐藏
-->
<template name="detailAdd">
<view hidden="{{isshowDetail===false}}" class="x-detailadd-cls animated {{isshowDetail==true ? 'fadeInUp': 'fadeOutDown'}}" >
<view class="x-detailadd-content">
<view class="x-detailadd-header">{{currentDetail.title}}<text bindtap="xdetailClose" class="x-detailadd-close"></text></view>
<view class="x-detailadd-content-box">
<view class="x-flex x-content-item margin-t-5">
<view class="x-content-item-title">数量:</view>
<view class="x-flex-item gzfs">
<text data-calc="1" bindtap="xdetailCalc" class="x-detal-label nomargin">-</text><input value="{{currentDetail.number}}" maxlength="2" type="number" class="x-detail-input"></input><text data-calc="2" bindtap="xdetailCalc" class="x-detal-label nomargin margin-l-30">+</text>
</view>
</view>
<view class="x-flex x-content-item">
<view class="x-content-item-title">是否加辣:</view>
<view class="x-flex-item"><text data-transle="false" bindtap="translatetap" class="x-detal-label {{currentDetail.isTranslate === false ? 'detailActive': ''}} ">否</text><text data-transle="true" bindtap="translatetap" class="x-detal-label {{currentDetail.isTranslate === true ? 'detailActive': ''}}">是</text></view>
</view>
<button style="width:100%;" bindtap="xdetailok" class="x-detailadd-button">确定</button>
</view>
</view>
</view>
</template>
- template/detailAdd.wxss
/*
@author: SM
@desc: 添加事项模版样式
*/
.x-detailadd-cls {
font-size:28rpx;
z-index: 9;
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, .5);
}
.x-detailadd-content {
position: absolute;
width: 100%;
z-index: 10;
bottom: 0rpx;
height: 400rpx;
background-color: #ffffff;
border-radius: 10rpx 10rpx 0px 0px;
}
.x-detailadd-header {
height: 80rpx;
line-height: 80rpx;
text-indent: 24rpx;
position: relative;
}
.x-detailadd-close {
display: inline-block;
position:absolute;
width: 15px;
height: 15px;
right: 20px;
top: 15px;
transform: rotate(45deg);
}
.x-detailadd-close::after {
content: '';
background: #999999;
height: 1px;
right: -1px;
top: 5px;
position: absolute;
width: 15px;
}
.x-detailadd-close::before {
content: '';
background: #999999;
height: 1px;
position: absolute;
width: 15px;
left: 1px;
top: 5px;
transform: rotate(90deg);
}
.x-detailadd-content-box {
background-color: #f7f7f7;
min-height: 100%;
}
.x-flex {
display: flex;
}
.x-flex-item, x-flex-item-1 {
flex: 1;
}
.x-content-item {
height: 40px;
line-height: 40px;
}
.margin-t-5 {
padding-top: 10px;
}
.x-content-item-title {
width: 200rpx;
padding-left: 16px;
}
.x-detailadd-button {
width: 100%;
margin-top: 30px;
height: 40px;
line-height: 40px;
text-align: center;
color: #fff;
background-color: #fe6701;
border-radius: 0rpx;
font-size: 30rpx;
position: absolute;
bottom: 0px;
}
.x-detal-label {
border:1px solid #ccc;
width: 60px;
height: 25px;
display: inline-block;
font-size: 13px;
line-height: 25px;
text-align: center;
color: #000;
background-color: #fff;
border-radius: 3px;
}
.x-detal-label:first-child {
margin-right: 10px;
}
.x-detal-label.detailActive {
background-color: #fe6701;
color: #fff;
border: transparent;
}
.x-detal-label.nomargin {
margin-right: 0px;
border-radius: 0px;
width: 40px;
background-color: #f2f2f2;
}
.x-detail-input {
display: inline-block;
width: 30px;
border:1px solid #ccc;
position: absolute;
top: 14.5rpx;
height: 25px;
border-left: none;
border-right: none;
background-color: #fff;
text-align: center;
}
.x-flex-item.gzfs {
position: relative;
}
.margin-l-30 {
margin-left: 30px;
}
.x-detail-view {
background: #fff;
margin: 0 15px;
height: 35px;
line-height: 35px;
margin-top: 10px;
}
.x-detailadd-view-cls {
/*font-size:28rpx;
border: 1px solid #c1c1c1;
height: 450rpx;
position: fixed;
left: 0;
right: 0;
bottom: 235rpx;
z-index:9;
border-radius: 5px;
border:1px solid red;*/
font-size:28rpx;
z-index: 9;
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 235rpx;
background: rgba(0, 0, 0, .5);
}
.x-detail-content-view-box {
overflow-y: auto;
height: 400px;
}
.x-detailadd-view-content {
height: 400px;
/* bottom: 150rpx; */
}
.x-detail-view-del {
font-size: 14px;
padding-right: 15px;
color: red;
}
.xdetailviewClean {
position: absolute;
right: 16px;
font-size: 14px;
}
- template/detailview.wxml
<!--
@author:SM
@desc: 查看事项模版视图
fadeInUp 显示
fadeOutDown 隐藏
-->
<template name="detailView">
<view hidden="{{isviewDetail===false}}" class="x-detailadd-view-cls animated {{isviewDetail==true ? 'fadeInUp': 'fadeOutDown'}}" >
<view class="x-detailadd-content x-detailadd-view-content">
<view class="x-detailadd-header">已选择菜品<text class="xdetailviewClean" bindtap="xdetailviewClean" >清空菜品</text></view>
<view class="x-detailadd-content-box x-detail-content-view-box">
<!--item-->
<block wx:for="{{selectDetailList}}" wx:for-item="item" wx:key="index">
<view class="x-flex x-content-item x-detail-view">
<view class="x-content-item-title x-flex-item">{{item.title}}</view>
<view data-delindex="{{index}}" class="x-detail-view-del" bindtap="xdetailviewdel">
删除
</view>
</view>
</block>
<!--item-->
</view>
</view>
</view>
</template>
-
utils/animate.wxss
内容太多了,github直接下载 https://github.com/YulRW/wx-Wechat-animate-demo
把util/animate.wxss放到工程相同目录 -
app.wxss
/* SM add 引入 样式 */
/*动画*/
@import "./utils/animate.wxss";
/*添加事项模版样式*/
@import "./template/detailAdd.wxss"
/* SM add 引入样式 */
网友评论