当前位置:   article > 正文

自学阉割版奶茶点单uniapp小程序

自学阉割版奶茶点单uniapp小程序

涉及技术

vue3+sass+typescript+pinia+uniapp+微信小程序基础

编写工具:Vscode、微信小程序开发

项目介绍

这是一个基于瑞幸咖啡点单小程序创建的一个仅用于自己学习uniapp技术的项目。此项目不涉及服务器、网络等知识,数据内容以及数据类型均由自己编写。

此项目共分为三大块(即三个tabbar页面):index页面、order页面、my页面。

项目制作

项目创建与配置基础

项目创建

创配置Vscode

  1. 安装uni-app插件:uni-create-view、uni-helper、uniapp小程序拓展
  2. 安装类型声明文件
  3. manifest.json配置weixin-appid
  4. 运行npm run dev:mp-weixin打包,生成dist文件夹dist/dev/mp-weixin
  5. 打开微信开发小程序,引入dist/dev/mp-weiixn,vscode更改自动更新微信小程序

项目基础配置

  • 安装类型声明文件
    pnpm i -D @types/wechat-miniprogram @uni-helper/uni-app-types
  • 配置tsconfig.json
    1. {
    2. "extends": "@vue/tsconfig/tsconfig.json",
    3. "compilerOptions": {
    4. "sourceMap": true,
    5. "ignoreDeprecations": "5.0",
    6. "baseUrl": ".",
    7. "paths": {
    8. "@/*": [
    9. "./src/*"
    10. ]
    11. },
    12. "lib": [
    13. "esnext",
    14. "dom"
    15. ],
    16. "types": [
    17. "@dcloudio/types", // uni-app API 类型
    18. "miniprogram-api-typings", // 原生微信小程序类型
    19. "@uni-helper/uni-app-types" // uni-app 组件类型
    20. ]
    21. },
    22. // vue 编译器类型,校验标签类型
    23. "vueCompilerOptions": {
    24. "nativeTags": [
    25. "block",
    26. "component",
    27. "template",
    28. "slot"
    29. ],
    30. },
    31. "include": [
    32. "src/**/*.ts",
    33. "src/**/*.d.ts",
    34. "src/**/*.tsx",
    35. "src/**/*.vue"
    36. ]
    37. }
  • 安装sass和sass-loader
  • 安装uni-ui和配置easycom,在项目中使用uni前缀的标签时,会自动导入uni-ui中对应的标签。 
    1. //安装uni-ui
    2. cnpm i @dcloudio/uni-ui
    3. //pages.json
    4. {
    5. "easycom": {
    6. "autoscan": true,
    7. "custom": {
    8. // uni-ui 规则如下配置
    9. "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
    10. }
    11. },
    12. }

项目基本框架

tabbar页面配置

在pages.json中配置所有页面

  • pages中,配置所有页面包括tabbar页面和非tabbar页面,当前需要创建三个tabbar页面(index、order、my)
  • 在src/pages/下创建页面文件夹,在此文件夹下创建对应页面vue文件(src/pages/index/index.vue)(src/pages/orders/orders.vue)...
  • 创建好三个页面并在pages中配置好后,在tabBar中配置所有tabbar页面,tabbar页面数量区间【2-5】。只有配置了tabbar后中才能显示底部导航栏
  1. {
  2. "pages": [ //pages数组中第一项表示应用启动页
  3. {
  4. "path": "pages/index/index",//相对src下页面vue文件位置
  5. "style": {
  6. "navigationBarTitleText": "uni-app", //此页面顶部栏标题
  7. "navigationStyle": "custom" //自定义此页面导航栏(顶部栏样式)
  8. }
  9. },
  10. {
  11. "path": "pages/my/my",
  12. "style": {
  13. "navigationBarTitleText": "my",
  14. "navigationStyle": "custom"
  15. }
  16. },
  17. {
  18. "path": "pages/order/order",
  19. "style": {
  20. "navigationBarTitleText": "order",
  21. "navigationStyle": "custom"
  22. }
  23. }
  24. ],
  25. // 设置 TabBar
  26. "tabBar": {
  27. "color": "#333",
  28. "selectedColor": "#27ba9b",
  29. "backgroundColor": "#fff",
  30. "borderStyle": "white",
  31. "list": [
  32. {
  33. "text": "首页",
  34. "pagePath": "pages/index/index",
  35. "iconPath": "static/tabbarICON/home_default.png",
  36. "selectedIconPath": "static/tabbarICON/home_selected.png"
  37. },
  38. {
  39. "text": "点单",
  40. "pagePath": "pages/order/order",
  41. //默认状态下此导航栏的图标
  42. "iconPath": "static/tabbarICON/category_default.png",
  43. //点击后的图标
  44. "selectedIconPath": "static/tabbarICON/category_selected.png"
  45. },
  46. {
  47. "text": "我的",
  48. "pagePath": "pages/my/my",
  49. "iconPath": "static/tabbarICON/user_default.png",
  50. "selectedIconPath": "static/tabbarICON/user_selected.png"
  51. }
  52. ]
  53. },
  54. "globalStyle": { //全局样式
  55. "navigationBarTextStyle": "black",
  56. "navigationBarTitleText": "uni-app",
  57. "navigationBarBackgroundColor": "#F8F8F8",
  58. "backgroundColor": "#F8F8F8",
  59. "enablePullDownRefresh": true
  60. },
  61. "subPackages": [ //分包配置
  62. 。。。
  63. ],
  64. "preloadRule": {
  65. // 配置哪个分页预加载哪些子包
  66. 。。。
  67. }
  68. }

项目页面制作

index页面

样式 
  • 首先将index页面分为三大块:顶部栏轮播图,中部主要内容区,和中部各个卡片内容区。
  • 拆分组件,减轻单个页面代码量。在index文件夹中创建components文件夹,存放有关index页面的所有组件,(LkSwiper:顶部广告轮播、OperateCard:操作栏、AdSwiper:广告栏、WelfareCard:福利中心、SaleRankCard:好喝榜),其中AdSwiper卡片可共用于其它页面,AdSwiper组件放在src下的components文件夹中,作为全局组件(src/components/AdSwiper.vue)。
  • 中部主要内容区宽度占比为96%,并垂直居中。
逻辑 
  • index作为进入小程序后的最先显示的页面,在生命周期onReady中获取到所有数据后,将所有数据传分配给所有子组件,子组件接收数据后并渲染。而不是每个子组件都请求一次数据。父组件在子组件标签中绑定数据属性,并传递数据,子组件使用defineProps接收数据。
    1. 父组件
    2. <AdSwiper :list="bannerList" />
    3. 其它父组件
    4. <AdSwiper :list="otherBannerList" />
    5. 子组件
    6. defineProps<{
    7. list:BannerItem[] //BannerItem为bannerList中成员的数据类型
    8. }>()
  • 对于全局组件,如AdSwiper组件,所接收的数据来自不同的父组件,在子组件标签中添绑定的属性需一致,如上list属性,属性值如bannerList则可以是不同的父组件数据。
  • 所有可点击区域(如图标、文字链接)都可用navigator标签包裹,直接将对应跳转页面路径写入navigator标签url属性中。
    1. <navigator url="/pages/my/my">....</navigator>
    2. 跳转到my页面
  •  到店取/幸运送功能,点击到店取或幸运送,跳转到pages/order/order页面,传入自取或外送信息标识参数,order页面接收标识,显示自取或外送。

order页面

 

基本样式
  • 首先分为三大块:顶部栏、中部内容栏、底部点单详细栏,前两大块分别对应两个组件OroderTopBanner、OrderTabCard。
    • order设置了自定义顶部栏样式,"navigationStyle": "custom",需要设置一个安全距离,避免顶部栏内容渗入到手机顶部任务栏中。
      1. <view class="viewport"
      2. :style="{ paddingTop: safeAreaInsets?.top + 'px' }" > .... </view>
      3. //获取安全距离,作为order页面padding-top
      4. const { safeAreaInsets } = uni.getSystemInfoSync();
    • 自提和外送选择器,没有在uni-ui找到合适的模板,自己写
    1. <template>
    2. ...
    3. <view class="pick-method" @tap="switchMethod">
    4. <view :class="isTakeOut ? '' : 'active'">自提</view>
    5. <view :class="isTakeOut ? 'active' : ''">外送</view>
    6. </view>
    7. ...
    8. </template>
    9. <script setup lang="ts">
    10. import { ref } from "vue";
    11. //通过isTakeOut决定是否为该view添加acitve类名,拥有active类名背景样式为蓝色
    12. let isTakeOut = ref(false); //true为自提,false为外送
    13. const switchMethod = () => {
    14. //点击pick-method切换
    15. isTakeOut.value = !isTakeOut.value;
    16. };
    17. const changeTakeout = (param?: string) => {
    18. //根据index页面跳转过来传递的参数标识,切换isTakeOut
    19. console.log(param);
    20. if (param === "0") {
    21. isTakeOut.value = false;
    22. } else if (param === "1") {
    23. isTakeOut.value = true;
    24. }
    25. };
    26. //将方法暴露出去,供此子组件的父组件order使用
    27. defineExpose({
    28. changeTakeout,
    29. });
    30. </script>
    31. <style lang="scss">
    32. .pick-method {
    33. width: 170rpx;
    34. height: 50rpx;
    35. display: flex;
    36. background-color: rgba(161, 156, 156, 0.507);
    37. border-radius: 13px;
    38. align-items: center;
    39. margin-right: 40rpx;
    40. view {
    41. width: 50%;
    42. height: 50rpx;
    43. line-height: 50rpx;
    44. border-radius: 16px;
    45. text-align: center;
    46. }
    47. .active {
    48. background-color: blue;
    49. color: white;
    50. border-radius: 13px;
    51. }
    52. }
    53. </style>
中部内容区
  • 中部内容分为两大区域:经典菜单和会员卡,通过左右滑动中部或直接点击tab栏可切换经典菜单和会员卡 。siwper具有两个swiper-item项,分别为经典菜单、会员卡。scroll-view和swiper的宽度限制在与屏幕宽度同宽,并且两个swiper-item项宽度继承swiper同宽。
  • swiper添加@change事件(current 改变时会触发 change 事件,event.detail = {current: current, source: source}),并绑定一个current属性,为swiper子项目siwper-item设置唯一标识item-goodsId,当前显示的swiper-item与swiper-item中的item-goodsId值和当前swiper属性current的值是否一致有关
    1. .tab-swiper {
    2. width: 100%;
    3. height: calc(100vh - 245rpx);
    4. .menu-card {
    5. background-color: rgba(198, 189, 189, 0.42);
    6. }
    7. .vip-card {
    8. width: 100%;
    9. background-color: rgb(43, 133, 79);
    10. }
    11. }

  • tab-bar中放置两个导航,为两个导航添加点击事件,并传入对应TABID,在点击经典菜单时调用switchTab方法并传入参数0,将参数0赋值给targetIndex。swiper中current属性获取最新的targetIndex为0,则显示item-goodsId为0的swiper-item项。自此,通过点击导航栏项切换swiper-item项 完成。
    1. <view class="tab-bar">
    2. <view
    3. class="tab-item"
    4. v-for="item in tabs"
    5. :key="item.TABID"
    6. :class="item.TABID === targetIndex ? ' active' : ''"
    7. @tap="switchTab(item.TABID)"
    8. >
    9. {{ item.title }}
    10. </view>
    11. </view>
    12. </view>
    13. <swiper class="tab-swiper" @change="onChange" :current="targetIndex">
    14. <swiper-item class="menu-card" item-goodsId="0">...</swiper-item>
    15. <swiper-item class="vip-card" item-goodsId="1">...</swiper-item>
    16. </scroll-view>
    17. //
    18. const tabs = [
    19. { TABID: 0, title: "经典菜单" },
    20. { TABID: 1, title: "会员卡" },
    21. ];
    22. let targetIndex = ref<number>(0); //tab切换目标组件
    23. //tab点击事件
    24. const switchTab = (goodsId: number) => {
    25. targetIndex.value = goodsId;
    26. console.log(targetIndex.value);
    27. };
    28. //swiper的@change事件,current的值发生改变后,
    29. const onChange = (e: any) => {
    30. targetIndex.value = e.detail.current;
    31. console.log(targetIndex.value);
    32. console.log(e.detail.current);
    33. };
经典菜单点单 
  • 在经典菜单中,分为左右两个不一致的可滑动区域。左侧内容为各种不同款的商品归类(导航),每个导航包含多中款的商品,在点击不同导航时,右侧滑动到对应商品种类区域。在滑动右侧商品时,某个种类商品区域到达swiper顶部边界,左侧跟随切换到对应导航(高亮)。
  • 左侧每个导航都有对应的tabId(要求tabId不为纯数字,而应是字符串如‘tab1’),通过tabId判断当前导航是否active高亮显示,右侧scroll-view中,绑定scroll-into-view属性,当scroll-into-view所绑定的值与scroll-view中的某个子项view的id值一致时,则自动滑动到该子项。即点击左侧某个导航时,触发switchMenuTab方法并传入当前导航的tabId,在switchMenuTab方法中,将参数值赋值给targetMenuIndex,从而改变右侧scroll-view中scroll-into-view的值,继而直接自动滑动到右侧scroll-view所有子项view中id与scroll-into-view的值一致的子项。点击左侧导航栏显示右侧对应区域就完成了。
    1. <scroll-view scroll-y class="left-tab">
    2. <view
    3. class="tab-item-title"
    4. v-for="item in allMenu"
    5. :key="item.tabid"
    6. @tap="switchMenuTab(item.tabid)"
    7. :class="item.tabid == targetMenuIndex ? 'active' : ''"
    8. >
    9. {{ item.categoryList[0] }} //导航名称
    10. </view>
    11. </scroll-view>
    12. <scroll-view
    13. scroll-y
    14. class="right-tab"
    15. :scroll-into-view="targetMenuIndex"
    16. @scroll="rightScroll"
    17. >
    18. <view
    19. class="tab-container"
    20. v-for="item in allMenu"
    21. :key="item.tabid"
    22. :id="item.tabid"
    23. >
    24. ...
    25. </view>
    26. </scroll-view>
    27. //
    28. let targetMenuIndex = ref("tab1"); //默认显示右侧第一个子项
    29. const switchMenuTab = (goodsId: any) => {
    30. targetMenuIndex.value = goodsId;
    31. console.log(targetMenuIndex.value, goodsId);
    32. };
  •  滑动右侧,左侧对应导航也同步高亮,计算右侧每个子项目view盒子顶部距离父盒子scroll-view,将所有处理后的距离存储到toTopDistance数组中。同时右侧scroll-view中添加@scroll事件,当用户滚动右侧scroll-view时,则触发rightScroll方法。
    1. let toTopDistance: any = [];
    2. const getRightTabInfor = () => {
    3. const instance = getCurrentInstance();
    4. const query = uni.createSelectorQuery().in(instance);
    5. // 获取右侧所有格子的信息
    6. query
    7. .selectAll(".tab-container")
    8. .boundingClientRect((data) => {
    9. const formatData = JSON.parse(JSON.stringify(data));
    10. for (let i = 0; i < formatData.length; i++) {
    11. console.log(formatData[i].top ) //获取的是每个子项顶部距离屏幕顶部的距离(px)
    12. // 获取所有子盒子距离父盒子顶部距离时
    13. let temp = (formatData[i].top - 260).toFixed(0); //需要减去大概整个顶部栏高度
    14. toTopDistance.push(temp); //将所有子项目的距离存储到toTopDistance数组中
    15. }
    16. })
    17. .exec();
    18. };
    19. const rightScroll = (e: any) => {
    20. //scroll事件可以获取当前一些信息
    21. let SCROLL_TOP = e.detail.scrollTop; //当前滚动的距离(从scroll-view框架顶部到内容超出框架顶部的距离)
    22. //当前超出框架顶部的距离大于等于0并且小于第二个盒子顶部距离框架顶部的距离时,左侧导航显示的是tab1导航
    23. if (0 <= SCROLL_TOP && SCROLL_TOP < toTopDistance[1]) {
    24. targetMenuIndex.value = `tab1`;
    25. } else if (toTopDistance[1] <= SCROLL_TOP && SCROLL_TOP < toTopDistance[2]) {
    26. targetMenuIndex.value = `tab2`;
    27. } else if (toTopDistance[2] <= SCROLL_TOP && SCROLL_TOP < toTopDistance[3]) {
    28. targetMenuIndex.value = `tab3`;
    29. } else if (toTopDistance[3] <= SCROLL_TOP && SCROLL_TOP < toTopDistance[4]) {
    30. targetMenuIndex.value = `tab4`;
    31. }
    32. };
    33. onMounted(() => {
    34. getRightTabInfor();
    35. });

自提外送选择器逻辑
  • 在OrderTopBanner子组件中的自提外送选择器,通过isTaKeOut的value布尔值来决定谁高亮蓝色背景。点击选择框调用switchMehtod方法,改变isTakeOut值来切换选项。
  • 同时定义changeTakeOut方法,到店取跳转到order页面传入参数为1,幸运送传入参数为2,此处并不是真正意义上跳转传参,而是在点击到店取/幸运送时,执行跳转并将参数保存到storage中,跳转至order页面后,在onShow中获取当前storage中的参数值,并立即清理该storage。
  • 获取到参数后,将参数传给子组件OrderTopBanner暴露的changeTakeOut方法,此方法获取参数判断是自取还是外送,从而改变isTakeOut的value值,继而改变选项框的高亮背景选项。
    1. 为幸运送和到店取添加tap事件
    2. uni.setStorageSync("order-key", '1'); //保存不同的参数到storage中
    3. uni.setStorageSync("order-key", '0');
    4. uni.switchTab({ //跳转到order页面
    5. url: /pages/order/order,
    6. });
    7. //OrderTopBanner
    8. ...
    9. const changeTakeout = (param?: string) => {
    10. console.log(param);
    11. //参数为0,说明是从幸运送跳转来的
    12. if (param === "0") {
    13. isTakeOut.value = false;
    14. } else if (param === "1") {
    15. isTakeOut.value = true;
    16. }
    17. };
    18. defineExpose({ //将changeTakeout方法暴露给父组件,因为参数只能从父组件获取
    19. changeTakeout,
    20. });
    21. ...
    22. // order/order
    23. 获取子组件
    24. <OrderTopBanner ref="RefChild" />
    25. const RefChild = ref(); //获取子组件实例对象
    26. const callChildFn = () => { //创建callChildFn方法调用子组件方法
    27. let orderKey = uni.getStorageSync("order-key"); //从storage中获取参数
    28. uni.removeStorageSync("order-key"); //获取后就移除该参数
    29. RefChild.value.changeTakeout(orderKey); //调用子组件的chagneTakeout方法,并传入参数
    30. };
    31. onShow(()=>{
    32. callChildFn() //在跳转到order页面后立即执行此方法
    33. })

订单栏
  • 订单栏分为有订单情况和没订单情况(isCollapsed为true),另一部分是弹出框(不使用自带弹出框)部分和弹出框遮罩层部分,当存在订单时,点击order-card会弹出弹出框,显示所有加入购物车的订单。
  • 在有订单情况下点击触发onTapUncollpasedBanner,弹出弹出框,显示遮罩层。通过动态style控制display的值。遮罩层就是低于弹出层层级一级的半透明灰黑背景,点击背景后关闭遮罩层和弹出层。
    1. const popup = ref();
    2. const popupOverlay = ref();
    3. let isPopupOverlay: boolean = false;
    4. let isShowPopup: boolean = false;
    5. let customPopupStyle = ref({
    6. display: "none",
    7. transform: "translateY(400rpx)",
    8. });
    9. let customPopupOverlayStyle = ref({
    10. display: "none",
    11. });
    12. const onTapUncollpasedBanner = () => {
    13. // 有订单,默认展开显示 订单,点击打开popup展示所有订单
    14. isShowPopup = !isShowPopup;
    15. isPopupOverlay = !isPopupOverlay;
    16. if (isShowPopup === false) {
    17. customPopupStyle.value.display = "none";
    18. customPopupOverlayStyle.value.display = "none";
    19. } else if (isShowPopup === true) {
    20. customPopupStyle.value.display = "flex";
    21. customPopupOverlayStyle.value.display = "block";
    22. }
    23. };

添加订单(加入购物车)
 
  • 新建商品详情分包src/pagesOrder,分包下创建两个页面GoodsDetail页面和Purchase页面,在pages.json中配置分包,在进入order页面时加载分包pagesOrder。
    1. "subPackages": [
    2. {
    3. // 进入order页后预加载一下分包
    4. "root": "pagesOrder",
    5. "pages": [
    6. {
    7. "path": "Purchase/Purchase",
    8. "style": {
    9. "navigationBarTitleText": "Purchase"
    10. }
    11. },
    12. {
    13. "path": "GoodsDetail/GoodsDetail",
    14. "style": {
    15. "navigationBarTitleText": "GoodsDetail",
    16. "navigationStyle": "custom"
    17. }
    18. }
    19. ]
    20. },
    21. {
    22. ....其它分包
    23. }
    24. ],
    25. "preloadRule": {
    26. // 配置哪个页面预加载哪些分包
    27. "pages/order/order": {
    28. "network": "all",
    29. "packages": [
    30. "pagesOrder"
    31. ]
    32. },
    33. {
    34. ...
    35. }
    36. }
  • 点击order页右侧商品,跳转到商品详情页面GoodsDetail并传入此商品编号,GoodsDetail页面接收商品编号,获取此商品数据。选择商品类型和数量,将此商品所有类型及数量的商品存放在currGoodsOrder数组中。
  • 点击+图标,新增一个此商品到currGoodsOrder中(currGoodsOrder.push()),点击➖图标减去最新添加的商品(currGoodsOrder.pop())。
  • 点击加入购物车,将所有商品currGoodsOrder存储到本地存储中,order获取后清除。
    1. //GoodsDetail页面
    2. const onAddShoppingCar = () => {
    3. ...
    4. // 添加入购物车
    5. // 跳转到order界面,并将当前订单商品传递给order
    6. uni.setStorageSync(
    7. "banner-orders",
    8. JSON.parse(JSON.stringify(currGoodsOrder))
    9. );
    10. uni.switchTab({
    11. url: "/pages/order/order",
    12. success: (success) => {
    13. uni.showToast({
    14. title: "添加成功",
    15. position: "center",
    16. });
    17. },
    18. });
    19. ...
    20. };
    1. //order页面接收加入购物车的商品数据
    2. // pushBannerOrders:获取新增购物车订单
    3. const pushBannerOrders = () => {
    4. // 从参数中获取新的order,并新增到bannerOrders中
    5. let order: OrderItem = Array.from(uni.getStorageSync("banner-orders"));
    6. removeDuplicateOrder(order);
    7. // 获取后清除这个order
    8. uni.removeStorageSync("banner-orders");
    9. };
    10. onShow(()=>{
    11. ...
    12. pushBannerOrdes();
    13. ...
    14. })

  • order页获取加入购物车数据后进行处理,(一次加入购物车的currGoodsOrder数据都是同一个商品,只是区分商品不同类型),对新数据进行去重等处理,调用removeDuplicateOrder方法。ordre页面有一个自己的bannerOrders数组,存放所有订单。第一次加入一种商品时,bannerOders为空,按currGoodsOrder商品类型划分,同一种类型的商品只显示一次,不同类型和不同商品都独占一行。重复的商品并且重复的类型都只显示一次。
    1. const removeDuplicateOrder = (ORDER: OrderItem[]) => {
    2. // 1.处理ORDER
    3. // 创建新数组接收去重后的ORDER
    4. let newOrders: OrderItem[] = [];
    5. // 在ORDER中,所有订单出了goodsCustom和goodsCustomFormat存在不一致外,无法通过深度判断goodsCustom(对象)去重,所以使用goodsCustomFormat是否存在相同的
    6. // 使用map存储判断后的数据
    7. let map = new Map();
    8. for (let item of ORDER) {
    9. if (!map.has(item.goodsCustomFormat)) {
    10. map.set(item.goodsCustomFormat, item);
    11. }
    12. }
    13. newOrders = [...map.values()];
    14. // 判断newORders中每个成员在ORDER中的数量并创建newOrdersNum变量接收
    15. let newOrdersNum: number[] = [];
    16. newOrders.forEach((item) => {
    17. let i = 0;
    18. ORDER.forEach((ITEM) => {
    19. if (ITEM.goodsCustomFormat === item.goodsCustomFormat) {
    20. i++;
    21. }
    22. });
    23. newOrdersNum.push(i);
    24. });
    25. // 将newOrdersNum数组中的数据按顺序赋值给每个newOrders中的成员的goodsNum属性
    26. for (let i in newOrders) {
    27. newOrders[i].goodsNum = newOrdersNum[i];
    28. }
    29. // newOrders中一定是同goodsId的商品,区分在同goodId是否有不同goodsCustomFormat,而newOrders是已经去重的数组,每个成员都是同goodsId不同goodsCustomFormat。
    30. // 在为bannerOrders注入数据时,判断如下:
    31. // 1.判断当前bannerOrders中是否存在当前需要注入的数据newOrders的商品种类(judge,判断bannerOrders中是否存在与newOrders中的goodsId一致的商品)
    32. // 1.1 newOrders中的商品在bannerOrders中存在,判断bannerOrders中该数据的goodsCustomFormat是否与当前newOrders中的某个成员的goodsCustomFormat一致
    33. // 1.1.1 item.goodsCustomFormat == ITEM.goodsCustomFormat即存在与newOrders中某个成员同商品同商品类型的数据,则增加bannerOrders中的goodsNum
    34. // 1.1.2 在bannerOrders中找不到同类型goodsCustomFormat的商品,则将newOrders中的该数据push到bannerOrders中
    35. // 1.2 newOrders中的商品在bannerOrders中不存在,即newOrders中的goodsId在bannerOrders中找不到,则直接将整个newOrders拼接到bannerOrders中(完成第一次添
    36. // 加购物车后,第二次不同的商品添加入购物车,直接将第二次的所有商品拼接到当前的bannerOrders中)
    37. let judge = bannerOrders.value.findIndex(
    38. (item: OrderItem) => item.goodsId === newOrders[0].goodsId
    39. );
    40. if (judge !== -1) {
    41. //1.1
    42. bannerOrders.value.forEach((item) => {
    43. newOrders.forEach((ITEM) => {
    44. // 1.1
    45. if (item.goodsCustomFormat == ITEM.goodsCustomFormat) {
    46. // 1.1.1
    47. item.goodsNum += ITEM.goodsNum;
    48. } else if (
    49. bannerOrders.value.findIndex(
    50. (item3) => item3.goodsCustomFormat === ITEM.goodsCustomFormat
    51. ) === -1
    52. ) {
    53. // 1.1.2
    54. bannerOrders.value.push(ITEM);
    55. }
    56. });
    57. });
    58. } else {
    59. // 1.2
    60. bannerOrders.value = bannerOrders.value.concat(newOrders);
    61. }
    62. };

my页面

  • my页面与index页面大致相同
个人信息修改页 

  • 个人信息页为属于my页面的分包下的一个页面myInfo。
  • 在myInfo页面中展示所有用户信息,并且可修改其中信息,修改后发送请求以更新数据。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/330184
推荐阅读
相关标签
  

闽ICP备14008679号