小程序实现外卖滑动菜单栏

目的:

分析:

布局:

上、可供选择的栏目、tabs

下:左类别 + 友相对应的菜品 + 悬浮购物车(position:fixed)

左:可滑动的类别选择、scroll-view

右:可滑动的对应菜品、scroll-view

功能:

加入购物车特效

栏目切换

JS计算价格

实际成品(未完善):

动手:

栏目切换:

    <view class="tabs-box"><block wx:for="{{ tabs }}" wx:key="unique"><view class="tabs-item {{currentTabsIndex==index?'selected':''}}" bindtap="onTabsItemTap" data-index="{{index}}">{{item}}</view></block></view>
.tabs-box{height: 70rpx;display: flex;justify-content: space-between;
}.tabs-item{width: 50%;color: #C7C7CB;font-size: 28rpx;align-items: center;justify-content: center;display: flex;border-bottom: 1rpx solid #D0D0D7;
}.tabs-item.selected{color: #ff7440;border-bottom: 2px solid #ff7440;
}
  //tab切换onTabsItemTap: function (event) {let that = this;//let index = event.detail.dataset.value?记不太清了、可以自己console一下let index = shop.getDataSet(event, 'index');this.setData({currentTabsIndex: index})//载入评论数据if (this.data.currentTabsIndex == 1) {comments.loadComments(this.data.id, (res) => {that.setData({'commentsInfo': res,});(res.code == 1) && that.calcComments(res.result);});}},

左边菜单栏:

差不多同理、设置好区域切换时显示不同的区域就行了

右边对应菜品:

此处用了个贝塞尔曲线、完成飞入购物车的特效

      <!-- 菜品内容 --><scroll-view scroll-y="{{true}}" style="height:900rpx;" bindscroll="scroll" scroll-into-view="{{toView}}"><view class="shopDishes"><view class="shopDishes-box" wx:for="{{ dishes }}" wx:key="unique"><view data-src="{{ item.img_url }}" bindtap="aloneImgPreview"><image class="shopDishes-img" src="{{ item.img_url ? item.img_url : '../../images/icon/blank.png' }}" mode="aspectFill"></image></view><view class="shopDishes-info"><text class="shopDishes-title">{{item.name}}</text>                            <text class="shopDishes-price">¥{{item.price}}</text>                      <text class="shopDishes-desc">{{item.description}}</text>   </view>  <!-- 点击事件 --><view class="good_box" hidden="{{hide_good_box}}"  style="left: {{bus_x}}px; top: {{bus_y}}px;"></view><view class="add" catchtap="touchOnGoods" forbid="{{true}}"><view class="calcPic"><image src="../../images/icon/plus.png" bindtap="dishesCalc" data-id="{{ item.id }}" data-char="add"></image></view>                                          </view>                <view class="calcPic subtract"><image wx:if="{{ item.counts>0 }}" src="../../images/icon/subtract.png" bindtap="dishesCalc" data-id="{{ item.id }}" data-char="subtract"></image><text wx:if="{{ item.counts>0 }}">{{ item.counts }}</text></view></view><view class="blankImg" hidden="{{ shopInfo.food[0].id }}"><image src="../../images/icon/blank.png"></image></view></view></scroll-view></view>

这里想用冒泡事件来完成点击加入购物车同时触发贝塞尔曲线的点击事件、然后小程序好像不太支持pointer-event事件、然后再父函数里做处理成功完成了

.shopDishes{background-color: #eee;
}.shopDishes-box{display: flex;background-color: #fff;margin-bottom: 10rpx;padding: 10rpx;
}.shopDishes-info{margin: 0 10rpx 10rpx 10rpx;display: flex;line-height: 2.0;flex-direction: column;
}.shopDishes-title{font-weight: 900;font-size: 30rpx;
}.shopDishes-price{color: red;
}.shopDishes-desc{overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 3;-webkit-box-orient: vertical;align-content: center;font-size: 22rpx;
}.shopDishes-img{height: 240rpx;width: 240rpx;margin: 10rpx;
}.add{/* pointer-events: none; */
}.calcPic{/* pointer-events: visiblePainted; */display: flex;position: absolute;right: 15rpx;align-items: center;
}.calcPic image{width: 35rpx;height: 35rpx;margin: 15rpx;
}.subtract{right: 75rpx;
}
  //scrollscroll:function(event){},//外卖计算dishesCalc:function(event){let dishesId = shop.getDataSet(event, 'id');let char = shop.getDataSet(event, 'char');let index = this._getIndexById(dishesId);let tempObj = {};for (let key in this.data.shopInfo.food) {let dishes = this.data.shopInfo.food[key]if (dishesId == dishes.id) {tempObj = this.data.shopInfo.food[key];break;}}//添加、增加if (char == 'add'){  if(this.data.shopInfo.food[index].counts > 0){this.data.shopInfo.food[index].counts += 1;// this.touchOnGoods();}else{this.data.shopInfo.food[index].counts = 1;}shopcar.add(tempObj, 1, this.data.shopInfo.name);              //数量增加} else {    shopcar.subtractCounts(dishesId)      //数量减少this.data.shopInfo.food[index].counts -= 1;}//渲染this.setData({dishes: this.data.shopInfo.food})},

贝塞尔曲线实现(计算出点、然后根据点画线):


app.js

  //飞入购物车特效、贝塞尔曲线flytocar: function(){//获取屏幕[宽、高]var that = this;wx.getSystemInfo({success: function (res) {that.globalData.ww = res.windowWidth;that.globalData.hh = res.windowHeight;}})},/*** @param sx 起始点x坐标* @param sy 起始点y坐标* @param cx 控制点x坐标* @param cy 控制点y坐标* @param ex 结束点x坐标* @param ey 结束点y坐标* @param part 将起始点到控制点的线段分成的份数,数值越高,计算出的曲线越精确* @return 贝塞尔曲线坐标*/bezier: function (points, part) {let sx = points[0]['x'];let sy = points[0]['y'];let cx = points[1]['x'];let cy = points[1]['y'];let ex = points[2]['x'];let ey = points[2]['y'];var bezier_points = [];// 起始点到控制点的x和y每次的增量var changeX1 = (cx - sx) / part;var changeY1 = (cy - sy) / part;// 控制点到结束点的x和y每次的增量var changeX2 = (ex - cx) / part;var changeY2 = (ey - cy) / part;//循环计算for (var i = 0; i <= part; i++) {// 计算两个动点的坐标var qx1 = sx + changeX1 * i;var qy1 = sy + changeY1 * i;var qx2 = cx + changeX2 * i;var qy2 = cy + changeY2 * i;// 计算得到此时的一个贝塞尔曲线上的点var lastX = qx1 + (qx2 - qx1) * i / part;var lastY = qy1 + (qy2 - qy1) * i / part;// 保存点坐标var point = {};point['x'] = lastX;point['y'] = lastY;bezier_points.push(point);}//console.log(bezier_points)return {'bezier_points': bezier_points};}

shop.js

import { Shopcar } from '../shopcar/shopcar-model.js';var shopcar = new Shopcar();Page({data:{currentTabsIndex: 0,  //Tabs选项卡当前indexdishesTabsIndex: 0,   //dishesTabshide_good_box: true,      //贝塞尔曲线},onLoad:function(options){this.busPos = {};             //购物车坐标this.busPos['x'] = app.globalData.ww / 4;      //落地点坐标this.busPos['y'] = app.globalData.hh - 10;},//飞入购物车特效touchOnGoods: function (e) {//如果非冒泡调用、不执行if(! e.target.dataset.char){return 0;}// 如果good_box正在运动if (!this.data.hide_good_box) return;this.finger = {};var topPoint = {};this.finger['x'] = e.touches["0"].clientX;this.finger['y'] = e.touches["0"].clientY;if (this.finger['y'] < this.busPos['y']) {topPoint['y'] = this.finger['y'] - 150;} else {topPoint['y'] = this.busPos['y'] - 150;}topPoint['x'] = Math.abs(this.finger['x'] - this.busPos['x']) / 2;if (this.finger['x'] > this.busPos['x']) {topPoint['x'] = (this.finger['x'] - this.busPos['x']) / 2 + this.busPos['x'];} else {topPoint['x'] = (this.busPos['x'] - this.finger['x']) / 2 + this.finger['x'];}this.linePos = app.bezier([this.finger, topPoint, this.busPos], 20);this.startAnimation();},startAnimation: function () {var index = 0,that = this,bezier_points = that.linePos['bezier_points'],len = bezier_points.length - 1;this.setData({hide_good_box: false,bus_x: that.finger['x'],bus_y: that.finger['y']})this.timer = setInterval(function () {index++;that.setData({bus_x: bezier_points[index]['x'],bus_y: bezier_points[index]['y']})if (index >= len) {clearInterval(that.timer);that.setData({hide_good_box: true,})}}, 15);},

计算部分比较冗杂、不好梳理、直接贴代码了、有用的取、抱歉!

shopcar-model.js

import { Base } from '../../utils/base.js';export class Shopcar extends Base {constructor() {super();this._storageKeyName = '';     //‘’、不同的商家下、对应不同的缓存};//添加、有则+1、无则新建add(item, counts, key){this._storageKeyName = key; let carData = this.getCarDataFromLocal();if (!carData) {carData = [];}let isHasInfo = this._isHasThatOne(item.id, carData);if(isHasInfo.index == -1){item.counts = counts;item.selectedStatus = true;carData.push(item);}else{carData[isHasInfo.index].counts += counts;}this.execSetStorageSync(carData);}//获取本地数据、flag获取勾选的商品getCarDataFromLocal(key, flag){if(key){this._storageKeyName = key;}let res = wx.getStorageSync(this._storageKeyName);if(!res){res = [];}if(flag){let newRes = [];for(let i=0, len=res.length; i<len; i++){if(res[i].selectedStatus){newRes.push(res[i]);}}res = newRes;}return res;}//判断是否存在_isHasThatOne(id, arr){let item, result = { index: -1 };for(let i=0, len=arr.length; i<len; i++){item = arr[i];if(item.id == id){result = {index: i,data: item};break;}}return result;}//商品总数、选中或未选中getCarTotalCounts(flag){let data = this.getCarDataFromLocallet counts = 0;for(let i=0, len=data.length; i<len ;i++){//选中if(flag){if (data[i].selectedStatus){counts += data[i].counts;}}//未选中else{counts += data[i].counts;}}return counts;}//修改商品数量、数量为0时删除_changeCounts(id, counts){let carData = this.getCarDataFromLocal(), hasInfo = this._isHasThatOne(id, carData);if(hasInfo.index != -1){if(hasInfo.data.counts > 0){carData[hasInfo.index].counts += counts;if ( carData[hasInfo.index].counts==0 ){carData.splice(hasInfo.index, 1);          }}}this.execSetStorageSync(carData);}//+addCounts(id){this._changeCounts(id, 1);}//-subtractCounts(id){this._changeCounts(id, -1);}//删除deleteDishes(ids){if(!(ids instanceof Array)){      //转为数组ids = [ids];}let carData = this.getCarDataFromLocal();for(let i=0; i<ids.length; i++){let hasInfo = this._isHasThatOne(ids[i], carData);if(hasInfo.index != -1){carData.splice(hasInfo.index, 1);}}this.execSetStorageSync(carData);}/*公开方法,缓存*/execSetStorageSync(data) {wx.setStorageSync(this._storageKeyName, data);}//除去缓存removeStorage(key){this._storageKeyName = key; let data = this.getCarDataFromLocal(this._storageKeyName);if( data.length>0 ){wx.removeStorageSync(this._storageKeyName);}}
}

小程序实现外卖滑动菜单栏相关推荐

  1. 微信小程序导航栏或菜单栏吸顶效果简单实现

    微信小程序导航栏或菜单栏吸顶效果简单实现 思路: 1.获取导航栏初始位置距顶部的距离s1(通过获取页面标签方法) 2.监听页面的滑动,获取滑动距离s2(使用onPageScroll) 3.当s2> ...

  2. 微信小程序-tab左右滑动切换

    微信小程序-tab左右滑动切换 一.简介 1.核心思想 二.实现 1.wxml实现 2.js实现 3.wxss实现 三.参考和总结 四.优化 0.效果图 1.每个tab长度自适应 2.先前隔tab点击 ...

  3. 小程序实现左右滑动切换菜单+瀑布流显示列表

    小程序实现左右滑动列表区域,切换菜单(横向滑动菜单,切换时自动设置选中的菜单窗口居中显示),加载显示对应瀑布流数据,页面滚动时,设置菜单栏是否置顶显示 自己写的一个demo(下载地址:https:// ...

  4. 微信小程序 - 实现左滑动删除功能

    微信小程序 - 实现左滑动删除功能 效果图: 实现过程: 一.wxml布局 这里我是先用了一个大盒子包裹小盒子,然后小盒子里面进行左右布局(左边为内容部分,右边为删除按钮)的方式实现的 <vie ...

  5. node.js基于微信小程序的外卖订餐系统 uniapp 小程序

    美食是人类永恒的话题,无论是在古代还是现代人们对美食都有一种非常的热爱在里面,但是随着时代的发展,人们可能没有更多的时间去研究美食,很多时候人们在下班或者放学之后更希望通过网络来进行订餐,为此我开发了 ...

  6. 骑手app、配送、外卖送餐、自动接单、进行中、待接单、移动端app、高保真原型、Axure原型、配送里程、结算、取货、送货、送餐订单、外卖平台、送餐小程序、外卖app、点餐平台、移动端骑手app

    骑手app.配送.外卖送餐.自动接单.进行中.待接单.移动端app.高保真原型.Axure原型.配送里程.结算.取货.送货.送餐订单.外卖平台.送餐小程序.外卖app.点餐平台.移动端骑手app Ax ...

  7. Vue表单双向绑定显示 ,小程序水果外卖水果外卖模式 水果外卖怎么做 做个水果蔬菜配送的小程序 外卖水果小程序 水果店小程序门店

    <div id="app"><p>input 元素:</p><input v-model="message" plac ...

  8. 微信小程序实现左侧滑动导航栏

    微信小程序实现左侧滑动导航栏 1.左侧滑动导航栏图如下 2.这是我们左侧滚动栏的代码 wxml <view class='under_line'></view><view ...

  9. 微信小程序 slider双向滑动渐变色

    微信小程序 slider双向滑动渐变色 要求: 两个slider组件,第一个slider组件的选择区域为渐变色,未选择区域为灰色:第二个slider组件的选择区域为灰色,未选择区域为渐变色.无论滑动哪 ...

最新文章

  1. laravel 5.5 整合 jwt 报错Method Tymon\JWTAuth\Commands\JWTGenerateCommand::handle() does not exist解决...
  2. shell命令之---LVM文件系统
  3. 2020-03-21
  4. JBPM学习笔记(1)
  5. 11.1.2 DOM
  6. SQL 查询语句总是先执行 SELECT?
  7. python如何绘制曲线图_只会柱状图、饼状图、折线图怎么行,来用Python画个热力图...
  8. spring mvc实例
  9. 网络共享服务器 samba
  10. JavaScript创建页面节点
  11. 福利 | 简历模板大放送
  12. java的输入输出流
  13. 网站漏洞整改报告公司之攻防方案
  14. length和length()
  15. 旁观OpenGL里的透视投影矩阵
  16. win10电脑蓝屏自动修复失败无法开机的解决
  17. C++ setsockopt() 函数
  18. IntelliJ IDEA单元测试入门
  19. PS磨皮教程系列一:什么叫磨皮以及什么适合磨皮
  20. ZLG CANalyst驱动安装报错

热门文章

  1. 程序员用哪种输入法好呢
  2. sql的coalesce函数用法
  3. Python实现三国武将出场次数排序
  4. Microsoft adCenter API Version 8(C#)
  5. RecyclerView实现分组效果,多种实现方式
  6. 国内下载centos的镜像网站大全
  7. 三、通过session操作hibernate(hql语句)
  8. Linux reboot命令
  9. 合并两个有序链表——递归与迭代
  10. 换机迁移很麻烦?魅蓝Note5一招搞定