APICloud AVM多端开发 | 《外卖app开发》项目源码的深度解析(下)

2023-12-27 13:20

本文主要是介绍APICloud AVM多端开发 | 《外卖app开发》项目源码的深度解析(下),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上周,我们分享了用APICloud AVM多端开发技术开发一款《外卖app开发》项目源码解析上篇,现在把下篇补足,希望能帮助开发者快速体验一套代码编译Android和iOS app+小程序。

这篇主要讲解菜单点餐页双向滚动交互、菜品加购处理、购物车和付款逻辑处理,以及用户中心开发。查看这篇时,可以先复习上篇:
[APICloud AVM多端开发 | 《外卖app开发》项目源码深度解析(上)(https://blog.csdn.net/weixin_43947457/article/details/111866041?ops_request_misc=&request_id=&biz_id=102&utm_term=APICloud%2520%25E5%25A4%259A%25E7%25AB%25AF%25E5%25BC%2580%25E5%258F%2591%25E6%25A1%2588&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-0-111866041.first_rank_v2_pc_rank_v29)

一 菜单点餐页面
在这里插入图片描述
分类和菜品的双向滚动交互
这个页面是一个左右分栏的布局。左边是菜单分类,右边的菜品。 有一组比较常见的交互:

滑动右侧菜品,左侧分类高亮会随其更改。
点击左侧菜品分类,右侧菜品回滚到到对应区域。
其中第一个交互相关逻辑类似于在开发商家主页的滚动 scroll-view 触发头部透明度的逻辑。 所以同样地为右侧的 scroll-view 绑定上 @scroll=“onScroll” 函数。

具体逻辑请参考源码的实现部分,获取滚动高度等和主页类似。

重点关注第二个交互的核心在于点击对应分类,右侧的 scroll-view 需要滚动到指定位置。 使用属性来进行位置绑定: scroll-top={scrollTo} 。此时只需要在左边的分类点击事件 @click=“switchCategory(index)” 计算出正确的 scrollTo 即可实现。

function switchCategory(index) {this.data.categoryIndex = index;this.data.CD = new Date().getTime() + 500; // 手动切换分类后需要锁定500毫秒 避免右侧scroll-view滚动时带来次生问题this.data.scrollTo = this.offsetList[index];
}

菜品和加购处理 (跨端特性处理)
在这里插入图片描述
的菜品有一个 @click=“openAdd(goods)” 事件,用于打开加购页面。

function openAdd(goods) {if (isMP()) {this.data.currentGoods = goods;wx.hideTabBar();} else {api.openFrame({name: 'goods_add',url: '../goods_add/goods_add.stml',pageParam: {goods}})}
}

这个函数中展示了端差异上的处理。因为小程序没有类似 APICloud 的 frame 的概念, 所以新弹出的页面在小程序上,是一个页面内部组件实现的。

当然这种方式 APP 原生端也是支持的。如果需要进一步提高性能,发挥原生优势,则可以使用原生端的frame 来完成。 此时,将目标页面封装在一个自定义组件中,并把当前菜品数据传递进去。

目前组件和 frame 页面的获参形式暂时不同。在 goods_add 这个组件中的 installed 生命周期中可以看到如下的兼容片段:

this.data.goods = this.props.goods ? this.props.goods : api.pageParam.goods;

在新展开的加购浮层上,看到了之前定义的 goods_action,所以大致逻辑也是获取商品数据和加购数,并实现一下addCart函数。 实际上这个页面很类似外卖app开发商品详情页,只是展示UI不太相同。

沉浸式状态栏 safe-area
在这个页面中,自己实现了一个顶部导航栏。沉浸式状态栏一般会需要获取状态栏高度等处理能力。 在 avm.js 中提供一个 safe-area 组件,用于自动处理异形屏的边界问题。

<safe-area><view class="header"><text class="title">菜单</text></view>
</safe-area>

在主页中,也看到相关编程式获取安全区域数据的代码:

this.data.safeAreaTop = api.safeArea ? api.safeArea.top : 0;

二 购物车页面 computed 计算和v-if的条件渲染
在这里插入图片描述
购物车页面是一个比较经典的展示相关页面内部逻辑的案例。

在页面初始化的时候, this.getCartData() 拿到本地存储的购物车所有的数据。

function getCartData() {let cartData = api.getPrefs({sync: true, key: 'CART-DATA'});if (cartData) {cartData = JSON.parse(cartData);this.data.cartData = cartData;this.generateCartList();setTabBarBadge(2, Object.keys(cartData).length);}
}

其中还混合了一个 generateCartList 逻辑。

function generateCartList() {let cartData = this.data.cartData;let arr = [];for (let i in cartData) {arr.push({checked: true, ...cartData[i]});}this.data.cartList = arr;
}

这是一个生成函数,是将保存的对象构建为页面所需要的数组结构,同时增加每一个元素的 checked 属性。 然后再页面部分通过 v-for 来循环当前购物车的数据。

<view class="main-cart-goods-item" v-for="item in cartList"><radio-box class="main-cart-radio-box" :checked="item.checked"onChange={this.radioToggle.bind(this)}:item="item"></radio-box><img class="main-cart-goods-pic" mode="aspectFill" src={{item.goods.thumbnail}} alt=""/><view class="main-cart-goods-info"><text class="main-cart-goods-name">{{ item.goods.name }}</text><view class="main-cart-flex-h"><text class="main-cart-goods-price-signal">¥</text><text class="main-cart-goods-price-num">{{ item.goods.curt_price }}</text><goods-counter onCountChange={this.countChange.bind(this)}:count="item.count" :item="item"></goods-counter></view></view>
</view>

注意到每一个条目的开头嵌套了一个 自定义组件。 这个组件担负的任务很简单,就是使用自定的样式来渲染一个单选框。当然 avm.js 自带的系统组件 radio 也是可以实现的。

computed 的使用
下面有一个全选按钮,用于控制是否全选。

function checkAll() {const checked = !this.allChecked;for (let i = 0; i < this.data.cartList.length; i++) {this.data.cartList[i].checked = checked;}
}

而这个函数第一行以来的 this.allChecked 则是一个计算属性。在 computed 中能找到它的实现:

function allChecked() {return !this.cartList.some((item) => { // 也可以使用 every 来修改相反逻辑实现return !item.checked;})
}

紧接着它下面还有另外一个计算属性: totalPrice :

function totalPrice() {// 先筛选出选中项let list = this.data.cartList.filter(item => {return item.checked;})// 再计算总和并且格式化结果return (list.length ? list.reduce((total, item) => {return total + item.goods.curt_price * item.count;}, 0) : 0).toFixed(2);
}

然后再模板中直接使用这个结果,即可完成总价的显示:

<view class="text-group"><text class="main-cart-footer-text">合计</text><text class="main-cart-footer-price">¥{{ totalPrice }}</text>
</view>

可以看到,计算属性 computed 是可以通过一些逻辑计算出需要的结果,并且会暴露给实例本身, 在模板中能够同数据一样绑定。 同时能够自动处理所依赖的数据变化,做出实时的更新。

v-if 条件渲染
在页面中,有一个变量标记 isEdit,用来表示当前页面是否是在处于编辑状态。

<view @click="toggleEdit"><text class="main-cart-finnish-text" v-if="isEdit">完成</text><view v-else class="main-cart-action"><img class="main-cart-action-icon" src="../../image/icon/icon-cart-edit.png" alt=""/><text class="main-cart-action-text">编辑</text></view>
</view>

根据编辑状态的切换,右上角的按钮文案变化为“完成”和“编辑”两种状态。这个时候就可以通过 v-if 来判断渲染。 下面的结算、移除按钮也是一样,只不过是在模板中使用了三元表达式来做显示。

<text class="main-cart-footer-btn-text">{{ isEdit ? '移除' : '去结算' }}</text>

三 用户页面
在这里插入图片描述
这个页面主要有两个要点:外卖app开发头部用户信息区域和订单列表。

头部用户信息
头部的用户信息需要在初始化的时候读取本地用户数据。

/*** 获取用户信息* @returns {boolean|any}*/
function getUser() {let user = api.getPrefs({sync: true,key: 'USER'});if (user) {return JSON.parse(user)}return false;
}

把获取到的用户数据作为一个普通的页面数据,用来渲染用户信息面板。 如果用户数据不存在,也就是未登录模式,则需要使用 v-if 条件渲染来展示登录界面。

<view class="user-info flex flex-h flex-center-v" v-if="userInfo" @click="logout"><img class="user-avatar" src={{userInfo.avatarUrl}} alt=""/><text class="user-name">{{ userInfo.nickName }}</text>
</view><view class="user-info flex flex-h flex-center-v" v-else @click="wxLogin"><img class="user-avatar" src="../../image/icon/icon-user-avatar.png" alt=""/><text class="user-name">使用微信登录</text>
</view>

登录逻辑
在未登录的情况下,上面的第二块会展示,点击触发 wxLogin 方法:

function wxLogin() {if (isMP()) {this.mpLogin();} else {this.doLogin({ssid: getDeviceId()});}
}

这里依然需要对特性平台差异化处理。因为原生端和小程序端使用微信登录是两个不同的逻辑。 源代码 /widget/pages/main_user/main_user.stml 中还展示了一些使用原生模块来调用微信来登录的逻辑。

登录成功以后,开始执行 loginSuccess ,可以保存相关用户信息和会话信息,以备以后的使用。同时还需要刷新用户的购物列表。 如果在真实项目中其他已经打开的页面也需要监测用户状态变化,可以借助广播事件来处理详细的逻辑。

function loginSuccess(userInfo) {api.setPrefs({key: 'USER',value: userInfo});this.data.userInfo = userInfo;this.getOrderList();
}

页面的下拉刷新
页面下拉刷新和触底加载依赖于 scroll-view 的相关事件绑定和实现。

<scroll-view scroll-y class="flex-1 main-user-scroll-view"enable-back-to-top refresher-enabledrefresher-triggered={{loading}}@refresherrefresh="onRefresh"><view v-if="orderList.length"><order-item :order="order" v-for="order in orderList"onOrderAction={this.orderAction.bind(this)}></order-item></view><view class="empty-block" v-else><empty-block text="暂无订单哦~" type="order"></empty-block></view>
</scroll-view>

其中 @refresherrefresh=“onRefresh” 就是在下拉刷新需要触发的逻辑。 refresher-triggered={{loading}} 就是下拉刷新的状态。(用于通知回弹和设置刷新中)。

function onRefresh() {this.data.loading = true; // 设置正在刷新if (this.data.userInfo) { //有用户信息了才刷新this.getOrderList();} else {setTimeout(_ => {this.data.loading = false;api.toast({msg: '请登录后查看历史订单'})}, 1000)}
}

主页的开发大致就完成了,下面关注一下付款下单的过程。

四 待付款页面 (表单数据)
在这里插入图片描述
该页面也比较简单,大多数实现的逻辑在前面的页面已经提及。 此外有一个输入框表单 ,用来收集用户的输入备注信息。

<view class="order-note"><text class="order-note-key">备注</text><input class="order-note-input" placeholder="如需备注请输入"onBlur="onBlur" maxlength="30" id="remark"/>
</view>

通过失去焦点事件 onBlur=“onBlur” 来动态获取数据。

function onBlur(e) {this.data.remark = e.target.value;
}

获取数据也还有其他多种方式,可以进一步参考组件 input以及其他表单组件文档。

开始提交订单,和服务器通信下单并且支付。下单完成后做一些联动处理:

function addOrder() {POST('orders/app_addorder', this.formData).then(data => {// 打开结果页api.openWin({name: 'pay_result',url: '../pay_result/pay_result.stml'});// 通知支付成功 刷新订单页面api.sendEvent({name: 'PAY-SUCCESS'})// 清空购物车api.setPrefs({key: 'CART-DATA',value: {}});setTabBarBadge(2, 0);})
}        

支付成功页面的跳转
在这里插入图片描述
下单支付后跳转到支付结果页面。(这个过程是模拟成功下单,中间可以参考微信登录过程嵌套第三方支付)


至此,所有的外卖app开发页面逻辑主线已经完成。应用中还有一些细节处理,可以参考源码和文档进一步学习研究。想快速上手APICloud AVM多端开发,可以查看快速上手教程:https://docs.apicloud.com/apicloud3/?uzchannel=3

这篇关于APICloud AVM多端开发 | 《外卖app开发》项目源码的深度解析(下)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/543269

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定