只要功夫深,菜鸟也能写出细节满满的古茗点单小程序

3,506 阅读9分钟

前言

写在项目前的话:

临近期末了,各学科纷纷结课,随之而来的是各个课设的纷至沓来。俗话说得好,大学生的生活前五个月是温水泡脚,那么最后一个月的就是将前五个月泡脚的水喝下去。作为一个平日里摸鱼摸惯的摸鱼王,课设是最为头疼却又逃不掉的一环。这次的课设,是要模仿一个微信小程序,按照功能的完成度和难度来打分。作为摸鱼王的我,自然而然想起了“看起来简单”又界面好看(主要是靠图片撑起来的颜值)且天天都在用的————古茗点单小程序。而在实现的过程中,我才发现原来看起来简单的古茗小程序实际上细节满满。让我这个摸鱼王叫苦连天。

05KW1)J%Z%[FAO%C@OS6D.jpg

效果展示(模仿的是上个版本的古茗小程序,因为在模仿小程序中古茗更新过一次

首页页面

IMG_0392.GIF

点单页面

IMG_0396.GIF

选购页面

IMG_0401.GIF

订单页面

IMG_0413.GIF

我的页面

IMG_0417.GIF

以上就是我们模仿的古茗小程序的主要功能。

一、开始前所需要的准备

二、初始化一个小程序

  1. 新建一个文件夹
  2. 打开小程序,新建一个小程序
  3. 目录结构,如下所示
WEAPP
| -cloudfunctions
| -miniprogram
|     - assets // 静态变量
|         -GIF  //抓取的GIF
|         -icons //源于iconfont的icon图标
|         -images//抓取的静态图片
|     - componnents //组件
|         - panel // 购物车组件
|     - database //数据库
|         - db.js //存放所有数据的地方
|     - pages //各个页面
|         -home //主页
|           -home.js//js文件
|           -home.wxss//css样式文件
|     - utils //全局函数
|     - app.js   			// 系统的方法处理文件
|     -app.json 			// 系统全局配置文件
|     -app.wxss 			// 全局的样式表
|     -config.json 		// 域名等配置文件
| -README 
  1. 小程序app.json文件配置
  "pages": [
    "pages/home/home",//主页
    "pages/jump/jump",//shopping假跳转页面
    "pages/shopping/shopping",//显示各个店面信息页面
    "pages/order/order",//点单页面
    "pages/my/my",//我的页面
    "pages/teaList/teaList",//奶茶点单页面
    "pages/orderDetail/index"//点单详情页面
  ],
  "permission": {
    "scope.userLocation": {
      "desc": "你的位置信息将用于小程序点单定位"
    }
  },    //请求访问用户地理位置(小程序使用位置所必要的)
  //窗口
  "window": {
    "backgroundColor": "#F6F6F6",//窗口背景色
    "backgroundTextStyle": "dark",// 下拉背景字体、loading 图的样式,仅支持 dark/light
    "navigationBarBackgroundColor": "#fff",// 顶部tab背景颜色
    "navigationBarTitleText": "古茗",//顶部显示标题
    "navigationBarTextStyle": "black"// 导航栏标题颜色,仅支持 black/white
  },
  //tab导航条
  "tabBar": {
    "selectedColor": "#000000", //选中时样式
    "borderStyle": "black", // tabbar上边框的颜色, 仅支持 black/white
     "backgroundColor": "#fff",//背景颜色
     
     
     
     /** * tab列表,最少2个,最多5个 
     * text: 对应文案
     * pagePath: 对应页面路由
     * iconpath: 图标对应路径
     * selectIconPath: 选中时的图标对应位置 
     **/
   "list": [
      {
        "text": "首页",
        "pagePath": "pages/home/home",
        "iconPath": "assets/icons/home.png",
        "selectedIconPath": "assets/icons/home-active.png"
      },
      {
        "text": "点单",
        "pagePath": "pages/jump/jump",
        "iconPath": "assets/icons/shopping.png",
        "selectedIconPath": "assets/icons/shopping-active.png"
      },
      {
        "text": "订单",
        "pagePath": "pages/order/order",
        "iconPath": "assets/icons/order.png",
        "selectedIconPath": "assets/icons/order-active.png"
      },
      {
        "text": "我的",
        "pagePath": "pages/my/my",
        "iconPath": "assets/icons/my.png",
        "selectedIconPath": "assets/icons/my-active.png"
      }
    ]
  },
  //全局调用的Vant组件
  "usingComponents": {
    "van-search": "./miniprogram_npm/@vant/weapp/search/index",
    "van-cell": "./miniprogram_npm/@vant/weapp/cell/index"
  },
  //默认样式
  "sitemapLocation": "sitemap.json",
  "style": "v2"
}

5.创建两个数据表

image.png

image.png

注意:一定要创建名字一样的数据表哦

这些弄完就可以开始做一个古茗点单小程序啦!

S9T[VACMF5C72W]65U1}W.jpg

三、开发时所遇到的问题以及解决方案

1. swiper 组件

在古茗小程序中,很多地方都用到了swiper组件,我们通过查阅文档,也都实现了古茗小程序所展示的效果 以下是一些我学习完后的心得

心得:

  1. swiper是滑块视图容器。其中只可放置组件,否则会导致未定义的行为。
  2. autoplay 类型是boolean 默认值是false 非必填 作用为:是否自动切换 我们将它的值改为true,它就会自动播放了
  3. circular 类型是boolean 默认值是false 非必填 作用为:是否采用衔接滑动
  4. 其中的swiper-item 都用占位符绑定了图片的位置和图片id

2.假页面跳转

@5L6%3A1COMQ18N6MK8K}ER.png

EPC0XRP)R{)OFFVHLTP_9.png

在开发中,我们发现古茗的shopping页面(即点单页面),当我们点击后,下面并没有出现导航栏,经过查询资料发现,小程序并没有提供让导航栏暂时消失的的方法,在我们摸不着头脑时。我们发现当点击点单页面时,出现页面跳转的效果。因此我们推断,这个选店的页面,可能只是普通的页面并非导航栏页面。(小程序中导航栏页面与普通页面有很多不一样的地方)

解决方案:

只要在导航栏页面中的onShow方法中,添加跳转页面的方法,让导航栏页面加载完后(但实际什么也没有写),自动跳转我们渲染好的页面即可(即真正的点单页面)。解决代码如下:

onShow: function () {
   
      wx.navigateTo({
        url: '/pages/shopping/shopping',
      })
    },

但随着假页面(跳转页面)的出现,同时也有很多问题浮出了水面。例如wx.navigateBack(跳回上一个或多级页面)方法失效问题。

R1K4S{J30QNPQY$74{6O28.png

当点击这个按钮时,要返回上一个页面 即使用wx.navigateBack 返回到上一页面或多级页面。无论设置返回上级多少个页面,他会一直会在此页面不动。

K2RCR%XHP3MOIWLTE30{IF.jpg

出现问题的原因:

因为我们设置了一个假页面,选择店面的页面上一级是我们设置的假页面,假页面中的onShow方法。当加载完后又会跳到选择门店页面,所以在此时wx.navigateBack就已经完全失效了。

三、wx.navigateBack失效问题

由第二点我们知道,在这种情况下wx.navigateBack已经完全失去他的作用。但在古茗小程序中,这个跳转又是不可缺少的,因为一旦缺少,就会出现严重的页面跳转的BUG。因此我们不得不想出新的解决方案。

解决方案:

经过讨论,我们选择重新写一个方法来实现wx.navigateBack既定的功能。我们发现,如果从主页点击点单页面,再返回,那么就是返回到主页。如果从订单页面点击到点单页面,那么就是返回到订单页面。如果从我的页面点击到点单页面,那么就是返回到我的页面。因此,我们认为在这三个(主页,订单页面,我的页面)onShow方法中,将它们的跳转地址交给Storage(储存器储存起来)。到需要用时再取出来: 解决代码如下:

将地址存进去

onShow: function () {
    wx.setStorageSync('address', "/pages/home/home");
  },//此为主页,其他三个页面依此类推

选择店面的页面中取出来

backLastPage() {
    let address = wx.getStorageSync('address')
      wx.switchTab({
        url: address,
      })
  
 },

此时,wx.navigateBack失效的问题就完全解决了

AAF7LQHT2BYNU64O6(5E9M3.jpg

你看,问题一个一个的来,一个一个解决不就行了。此时的我直接杀神附体,感觉什么问题都能KO

L)R@4B3LLGPGH@4.jpg

四、自定义顶栏的样式

image.png

我们发现,我们在app.json中这样设置,是全局性质的。但我们在选择店面的页面中,它的顶栏和全局的顶栏是不一样的

image.png

因此,我们需要diy选择店面的页面顶栏。我们只需要在需要diy的页面中的json的文件中添加"navigationStyle": "custom"就可以自己用wxss写出一个顶栏了

五、小程序中map组件的运用

腾讯位置服务推出《微信小程序解决方案》,从检索API、基础地图组件、个性化、插件、行业方案等多个层面,为不同场景需求的小程序开发者提供完整的地图能力。 个性化地图在小程序中,是已经给出了map组件的,因此运用起来是非常方便的。 以下,是我们设计的古茗小程序的map组件运用的一些总结:

  1. longitude 类型为number 无默认值 是必填的 作用是提供中心经度
  2. latitude 类型为number 无默认值 是必填的 作用是提供中心纬度
  3. scale 类型为number 默认值为16 不是必填 作用是用鼠标滑轮控制缩放级别,取值范围为3-20
  4. show-location 类型为boolean 默认值为false 不是必填的 作用是显示带有方向的当前定位点
  5. markers 类型为Array.marker 无默认值 不是必填的 标记点用于在地图上显示标记的位置(即奶茶店的位置) 而markers也是值得研究的

markers:

  1. id |类型为number 无默认值 不是必填的 marker点击事件回调会返回此id
  2. latitude | 类型为number 无默认值 是必填的 浮点数,范围 -90 ~ 90
  3. longitude | 类型是number 无默认值 是必填的 浮点数,范围 -180 ~ 180
  4. iconPath |类型是string 无默认值 是必填的 支持网络、本地、代码包路径
  5. width |类型是number/string 无默认值 不是必填的 默认为图片实际宽度
  6. height | 类型是number/string 无默认值 不是必填的 默认为图片实际高度

在我们模仿的古茗小程序中,由于没有店面的实体数据,没办法完全模拟古茗小程序,但为了增加使用者的体验感,我们写了个方法————获取到使用者当前的位置。并以使用者为原点,建立平面坐标系。生成了六个店面(位置随机),但店面的名字都是死数据。最大可能的模仿了古茗小程序的地图功能,实现代码如下:

onLoad: function () {
  var that = this;
  wx.getLocation({
    type: 'gcj02',
    success: (res) => {
      var latitude = res.latitude
      var longitude = res.longitude
      that.setData({
        latitude: latitude,
        longitude: longitude,
      })      
    }
  })//获取自身位置

@Y(OCUK2(TCWTPO~GNZZUMH.jpg

虽然这些都没有学过,但还是通过我查阅资料,没想到最终还是被我给解决了,此时浓浓的成就感就油然而生了

ACQT%DK3U7Q7L1TOH%_P4.jpg

六、选择店面时,出现黄色边框以及确认店面提示框。

通过之前的效果展示,我们可以看见在选择店面的页面,我们选择不同的店面时,那店面信息四边会出现黄色的边框来表现已经选中,同时会出现对话框来确定这家店的信息。

要实现这个效果,我们首先得在写wxml时,在可点击的店面(view)中分别绑定data-index,在最外层bindtap绑定的方法中获取所点击的view的index值,再将index的值赋给我们所设的变量activeNavIndex

image.png

image.png

image.png

然后在wxml中用一个三元运算符进行判断

image.png

最后在wxss中写出默认时的样式和点击后的样式

image.png

这里有两个值得注意的点:

  1. activeNavIndex(我们所设置的变量)默认值应该为0,这样当我们不点击时就会默认第一家店出现黄色边框,这样符合我们的设计要求。如果以后需求不同(如都是默认样式又或者是最火爆的店面先出现黄色边框),也可以根据自己的需求设置
  2. 默认样式中,也要设置边框(这里运用的是border),宽度要和点击后的宽度一致,达到控制变量的效果。但默认的时候,可以将边框设置成白色或者添加透明度,让其“消失”。如果不加默认样式时的边框,那么点击后全局的样式就会改变,非常的别扭。

然后就是点击后出现的对话框了,小程序中给了一个wx.showModal方法

image.png

在小程序中,非常方便的写出了对话框,这也是小程序的优点之一,开发非常的方便。

HW5JOPQ4PSU2A(R@B.jpg

七、选商品页面菜单的开发

image.png

其实一开始要我解决这个问题,我是拒绝的,我毕竟可是摸鱼王,这么难的问题怎么可能交给我?我当时本来就想偷偷的划水。但想起我之前碰见的问题都解决的那么漂亮总不能在这半途而废吧。于是我又开始翻翻翻....

{)ZFD@{O(EHpg

后来我发现,这个菜单还是有迹可循的,其中左边菜单栏的开发类似于第六点,也是添加点击事件,然后埋下index...... 不过值得一提的是,这里由于我wxml设计的一些原因。用border-left达不到我们所想要的效果,于是我们运用了另一个方法来添加点击后的样式。那就是————做了一个伪类,也算是这类问题的另一种解决方案了吧,如果以后碰见需要点击后的样式更花哨,更复杂的需求的话。伪类应该可以给你一个更大的发挥空间。

image.png

44T(O(_39{HAL90NM737LXT.gif

然后右边的商品栏才是这个问题的难点了。在解决这个问题前,我们得先来学习一下小程序中的scroll。

@D1WC25VY%04MST5P$9FB.jpg

scroll总结:

  1. scroll-y 类型为boolean 默认值为false 不是必填的 作用是允许纵向滚动
  2. scroll-with-animation 类型为boolean 默认值为false 不是必填的 作用是在设置滚动条位置时使用动画过渡
  3. enable-back-to-top 类型为boolean 默认值为false 不是必填的 作用是iOS点击顶部状态栏、安卓双击标题栏时,滚动条返回顶部,只支持竖向
  4. scroll-into-view 类型是string 无默认值 不是必填的 作用是值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素
  5. scroll-top 类型是number/string 无默认值 不是必填的 作用是设置竖向滚动条位置
  6. bindscroll 类型是eventhandle 无默认值 不是必填的 作用是滚动时触发,event.detail = {scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY}

知道这些基础知识后,我们来走进这个难点。

首先,数据的设计就十分讲究

 {
    title:'当季新品',
    products:[
      {
        title:'生椰拿铁冰激淋',
        tag:'新品',
        desc:'珍珠、冰激淋、生椰乳、咖啡液、牛奶生...',
        price:'16',
        pic:'https://img.gumingnc.com/newton/20210719053749CST84721626687469148.png?x-oss-process=image/resize,w_204,m_lfit '
      },
      {
        title:'龙井奶芙',
        tag:'新品',
        desc:'龙井、鲜奶乳、奶芙顶、坚果碎色清味...',
        price:'16',
        pic:'https://img.gumingnc.com/newton/20210719041227CST36011626682347798.png?x-oss-process=image/resize,w_204,m_lfit'
      },
      {
        title:'泡鲁达',
        tag:'新品',
        desc:'西米、多肉、红宝石、椰香白糯米、桂花...',
        price:'17',
        pic:'https://img.gumingnc.com/newton/20210609082139CST16401623241299533.png?x-oss-process=image/resize,w_204,m_lfit'
      }
     
    
  
    ]
   }

这是其中一个分类的所有数据。该项目有十一个这样的类

其次是wxml的布局,也很讲究,其布局大概是这样的

image.png

了解了结果,然后开始完成其功能了。 首先,因为scroll-into-view接收的是一个id,所以我们给每一个大类埋下一个index,加一个id='position{{index}}',然后我们在左边导航栏的中的点击事件添加一个setData。因为在左边我们也埋下了一个index,所以两边的index是一一对应的。所以有

this.setData({ 
        idx: e, 
        toView: 'position' + e 
      })

此时,我们再加上scroll-with-animation,将其的值设为true。此时,我们点击左边的导航栏时,右边就将商品对应上了。 然后,我们在onLoad函数中,将所有的类名带position的view筛选出来(注:一个大类的类名class='scroll-box position')

 wx.createSelectorQuery().selectAll('.position').boundingClientRect(function (rects) {
        
        that.setData({ positions:rects })
      }).exec();

这里的rects返回的是一个数组,其中包含所有类名带position的节点信息,返回的节点信息中,每个节点的位置用leftrighttopbottomwidthheight字段描述。如果提供了callback回调函数,在执行selectQuery的exec方法后,节点信息会在callback中返回。这样,每个大类的信息就被储存起来了。

最后,就是写bindscroll函数了,

image.png

如果这个大类距离顶部小于等于滚动条加swiper宽度的话,我们就把她加进arr这个空数组, 最后拿到可视范围的大类之前埋入的index。返回给左边导航栏的idx,这样相对应的左边导航栏就会出现选中样式。如此,一个成功的菜单就完成了!

DUJ8NBJ%LU_R6Y0.gif

八、用户的等级制度以及满十赠一活动

这个可以说是比较简单的一个方法了,但却极大的增加了用户的交互。看起来高大上实际却又十分简单。 首先,从用户表中,拿出历史总杯数。也拿出此时用户的VIP等级。

image.png

以上,就是这个项目我们所解决的问题了

注意:

此处,由于数组的特性以及没有VIP等级大于等于0,等级和经验条一一对应。即达到一级需要六杯,二级需要十二杯,三级需要18杯,四级需要30杯......如果达到了经验条则等级加一。如果没达到,返回当前等级。

四、总结

本次开发,学到了很多小程序有关的知识。想起一路上碰到的困难,此刻终于也能画上一个圆满的句号。相比起知识储备,解决问题的方法和思维才是更为重要的东西。一路上磕磕碰碰,也算是干了这五个月的洗脚水吧。在开发过程中,我也深刻的感觉到,微信小程序确实对新人很友好,很多方法小程序都给了现成的。非常的方便(手动点赞),小程序真的很适合新人学习前端。可以当作前端的敲门砖哦,毕竟这么菜的我,也能写出这样的小程序(不是自卖自夸)。小程序是真的是你下一点功夫,就能立竿见影的一门学问了。

另外,此次项目中仍有许多功能不够完善,一些细节还可以继续优化,路漫漫其修远兮。希望大家能给出宝贵的意见,如果文章中有错误和不足欢迎批评指正。也欢迎和我在评论区讨论各种有关小程序的问题哦~

如果你觉得这篇文章让你学习到了知识的话,麻烦给个免费的赞呗~,这对创作者真的很重要T.T

另外另外项目地址也想要个免费的star(づ。◕‿‿◕。)づ★

{NM%GV`HH04Z_4T0}E.jpg