微信小程序(初学篇)——仿美团外卖 不念不忘少年蓝@ 2022-06-11 01:22 349阅读 0赞 初识[小程序][Link 1],为它的小巧玲珑所吸引,不由得心血来潮。这不正是用户所需要的吗?既方便快捷,又不占手机内存。所以我下定决心一定要做出一个自己的小程序,然后赚钱、赚钱、赚钱...当然现在只是学习阶段,所以先仿一个高端产品来挑战自我吧。说到高端,自然然而的就想到了美团。之后噼里啪啦一顿忙乎,终于做出了一点样子来,希望能为同为小白的同学们提供一点帮助和参考,现在我们进入正题。 开发工具 微信web开发者工具: 官网就可以下载,相信大家早就安装好了吧。 小程序 API: 官网提供的文档,不懂得地方多看两遍基本上就可以解决了。 Easy Mock: 一个能够提供虚拟数据接口的网站,在前端独自开发的情况下,实在是再好不过的工具了。 功能 已经实现的功能: 主界面 订单界面 用户界面 点菜界面 定位界面 未实现的功能: 数都数不清,毕竟大企业的产品,不是说模仿就模仿的,所以只实现了一些主要的功能,和一些能力之内的功能... 项目启动 创建界面 1."pages":[ 2."pages/home/home", 3."pages/menu/menu", 4."pages/location/location", 5."pages/my/my", 6."pages/order/order" 7.], 只要编辑app.js中的pages属性,就会在项目目录下的pages文件夹里自动生成一个文件夹,里面包扩了.wxml 、 .wxss 、 .json 、 .js这样四个文件。wxml就是界面结构文件, .wxss就是样式文件, .js是用来存放js代码并实现界面逻辑的地方,至于 .json就是用来配置页面属性的地方,如:修改标题栏的颜色,和文字。 配置标题栏的样式 1."window":{ 2."navigationBarTitleText": "美团外卖+", 3."navigationBarTextStyle": "white", 4."navigationBarBackgroundColor": "#FFC640" 5.}, 同样是在app.json中配置,其他页面的标题栏都以此为例。 添加底栏 1."tabBar": { 2."color": "#272636", 3."selectedColor": "#FFD161", 4."backgroundColor": "#fff", 5."borderStyle": "#a8a8a8", 6."list": [ 7.{ 8."pagePath": "pages/home/home", 9."iconPath": "pages/images/home.png", 10."selectedIconPath": "pages/images/home-selected.png", 11."color":"white", 12."text": "首页" 13.}, 14.{ 15."pagePath": "pages/order/order", 16."iconPath": "pages/images/order.png", 17."selectedIconPath": "pages/images/order-selected.png", 18."text": "订单" 19.}, 20.{ 21."pagePath": "pages/my/my", 22."iconPath": "pages/images/my.png", 23."selectedIconPath": "pages/images/my-selected.png", 24."text": "我的" 25.} 26.] 27.} 在app.json中编写以上代码,这是小程序自带的功能,只需要照搬照抄就可以了,极其方便,效果如下: [![080221v9j3yyi3e2yzuary.gif][]][080221v9j3yyi3e2yzuary.gif] image 数据请求 1./** 2.* 生命周期函数--监听页面显示 3.*/ 4.onShow: function () { 5.var that = this; 6.wx.request({ 7.url: "https://www.easy-mock.com/mock/596257bc9adc231f357c4664/restaurant/info",//easy-mock生成的虚拟数据接口链接 8.method: "GET", 9.success: function (res) { //成功得到数据,对数据进行处理 10.that.setData({ //将数据发送到data中 11.restaurant: res.data.data.restaurant, 12.location: wx.getStorageSync('location') 13.}) 14.} 15.}); 16.}, data是每个页面.js文件中都存在的一个键,用来储存本页面需要用到的数据。具体使用,可在wxml文件中用\{ \{'data中的键名'\}\}的形式调用数据。 虚拟数据大致如下: 1.{ 2."success": true, 3."data": { 4."restaurant": [{ 5."name": "御膳房", 6."src": "http://i2.kiimg.com/601998/a955867016875a41.jpg", 7."star": 4.5, 8."sales": 641, 9."initial_price": 0, 10."distribution_price": 0, 11."distance": "156m", 12."time": 33 13.}, { 14."name": "韩式炸鸡啤酒屋", 15."star": 4.5, 16."sales": 731, 17."src": "http://i4.piimg.com/601998/9ce47f2f19d7717d.jpg", 18."initial_price": 15, 19."distribution_price": 0, 20."distance": "1.3km", 21."time": 52 22.},{ 23.//略去 24.},{ 25.//略去 26.},{ 27.//... 28.}] 29.} 30.} 主界面 效果图: [![080222xf8j9qm806qtfo8f.gif][]][080222xf8j9qm806qtfo8f.gif] image swiper控件应用 首先是两页标签的滑动切换,这里使用的是swiper,它是一款小程序自带的滑块组件,使用掌握起来非常简单,具体代码如下: 1.<swiper class="categoryList" indicator-dots="true" 2.indicator-color="rgba(228,228,228,1)" 3.indicator-active-color="#FECA49"> 4.<block wx:for="{ {categoryList}}" wx:key=""> 5.<swiper-item> 6.<block wx:for="{ {item}}" wx:key=""> 7.<view class="category-info"> 8.<image src="{ {item.src}}" 9.class="category-image"></image> 10.<view class="category-text">{ {item.name}}</view> 11.</view> 12.</block> 13.</swiper-item> 14.</block> 15.</swiper> swiper标签就是滑块组件的主体,表示可以滑动的区域,其中indicator-dots属性是设置设置点是否显示。接下来swiper-item标签在swiper之中表示的是每一个用来作为滑动的页面。这里用包裹着swiper-item表示的是使用categoryList对象数组中数据来循环渲染swiper-item,swiper-item的数量取决于categoryList中有多少组数据。之后在swiper-item中的block标签表示的是在一个页面中用categoryList.item中的数据循环渲染多个类似的标签,这些标签就是效果图中的类别项,总共两页,每页八个。这就是swiper和循环渲染的一些基本用法。 弹出层的实现 1.<view class="mask" 2.hidden="{ {mask2Hidden}}" bindtap="mask2Cancel"> 3.<template is="sort_list" data="{ {selected,sortSelected}}"/> 4.<scroll-view class="filterList" scroll-y="true" > 5.<view class="filterList-characteristic-title">商家特色</view> 6.<view class="filterList-characteristic-items"> 7.<block wx:for="{ {characteristicList}}" wx:key=""> 8.<view class="filterList-characteristic-item { {characteristicSelected[index]==true?'characteristic-selected':''}}" 9.catchtap="characteristicSelected" data-index="{ {index}}">{ {item.text}}</view> 10.</block> 11.</view> 12.<view class="filterList-discount-title">优惠活动(单选)</view> 13.<view class="filterList-discount-items"> 14.<block wx:for="{ {discountList}}" wx:key=""> 15.<view class="filterList-discount-item { {discountSelected==index?'discount-selected':''}}" 16.catchtap="discountSelected" data-index="{ {index}}"> 17.<text class="filterList-discount-item-icon" 18.style="background:{ {item.iconColor}}">{ {item.icon}}</text> 19.{ {item.text}}</view> 20.</block> 21.</view> 22.</scroll-view> 23.<view class="filterList-footer"> 24.<view class="filterList-footer-delect" 25.catchtap="clearSelectedNumb">清除筛选</view> 26.<view class="filterList-footer-finish" bindtap="finish">完成 27.<view class="filterList-footer-finish-number" hidden="{ {selectedNumb==0}}">{ {selectedNumb}} 28.</view> 29.</view> 30.</view> 31.</view> 最外层的mask类的view就是一个遮罩层,用来覆盖之前的界面形成遮罩的效果,并在上面显示新的界面也就是弹出层。以上的代码就是效果图中点击筛选按钮所呈现出来的内容了。其中bindtap属性就是点击事件的绑定了,具体的点击事件需要在.js文件中设置。值得一提的是,bindtap事件是会把当前标签受到的点击冒泡给它的父容器,这就相当与同时点击了他的父容器,如果想阻止冒泡的话就需要使用catchtap。 定位界面 先上效果图: [![080222yfu5msux91rwo7wz.gif][]][080222yfu5msux91rwo7wz.gif] image 页面结构: 1.<view class="header"> 2.<view class="search-input"> 3.<input placeholder="请输入收货地址" 4.bindinput="input"></input> 5.</view> 6.<view class="search-btn">搜索</view> 7.</view> 8.<view class="result-container" hidden="{ {hidden}}"> 9.<scroll-view scroll-y="true"class="search-result-list" hidden="{ {hidden}}"> 10.<block wx:for="{ {locationList}}" wx:key=""> 11.<view class="search-result" bindtap="onTap" data-key="{ {item.address}}">{ {item.name}} 12.<view class="search-result-desc">{ {item.address}}</view> 13.</view> 14.</block> 15.</scroll-view> 16.</view> 17.<view class="getLocation" 18.bindtap="getLocation">点击定位当前位置</view> 19.<view class="addLocation">新增收货地址 20.<view class="addLocation-icon">+</view> 21.</view> 22.<view class="myLocation">我的收货地址</view> 23.<view class="LocatonInfo"></view> 24.<view class="userTel"></view> 这个界面主要涉及到的就是弹出层和百度地图API的调用,调用方法可以查看百度地图API,具体点击事件代码如下: 1.getLocation: function () { 2.wx.getLocation({ 3.type: 'gcj02', 4.success: function (res) { 5.var latitude = res.latitude 6.var longitude = res.longitude 7.wx.request({ 8.url: 'http://api.map.baidu.com/geocoder/v2/?ak=btsVVWf0TM1zUBEbzFz6QqWF&coordtype=gcj02ll&location=' + latitude + ',' + longitude + '&output=json&pois=0', 9.method: "get", 10.success: function (res) { 11.console.log(res.data.result.formatted_address) 12.wx.setStorageSync('location', 13.res.data.result.formatted_address.substr(res.data.result.formatted_address.indexOf('市') + 1, 10)) 14.} 15.}) 16.} 17.}) 18.wx.switchTab({ 19.url: '/pages/home/home' 20.}) 21.}, 22.input: function (e){ 23.if(e.detail.value){ 24.this.setData({ 25.hidden: false 26.}) 27.this.search(e.detail.value); 28.}else{ 29.this.setData({ 30.hidden: true 31.}) 32.} 33.}, 34.search: function (text){ 35.var that = this; 36.wx.request({ 37.url: 'http://api.map.baidu.com/place/v2/search?query=' + text +'&page_size=20&page_num=0&scope=2®ion=南昌&output=json&ak=btsVVWf0TM1zUBEbzFz6QqWF', 38.success: function(res){ 39.console.log(res); 40.that.setData({ 41.locationList:res.data.results 42.}) 43.} 44.}) 45.}, 点菜界面 效果图如下: [![080223cdimkidpe3de22ex.gif][]][080223cdimkidpe3de22ex.gif] image 页面结构如下: 1.<import src = "../common/orderPage.wxml"/> 2.<import src = "../common/commentPage.wxml"/> 3.<view class="container" disable-scroll="true"> 4.<view class="header"> 5.<block wx:for="{ {swiperTitle}}" wx:key=""> 5.<view class="title { {index==currentPage?'selected':''}}" data-index="{ {index}} 6.bindtap="turnPage">{ {item.text}}</view> 7.</block> 8.</view> 9.<swiper class="swiper" current="{ {currentPage}} 10.bindchange="turnTitle"> 11.<swiper-item id="orderPage"> 12.<template is="orderPage" data="{ {menu,selected,howMuch,cost,pullBar}}"/> 13.</swiper-item> 14.<swiper-item id="commentPage"> 15.<template is="commentPage" data="{ {categoryList}}"/> 16.</swiper-item> 17.<swiper-item id="restaurantPage"></swiper-item> 18.</swiper> 19.</view> 菜单页面如下:`<template name="orderPage">` `2.<scroll-view class="orderPage-sideBar"` `3.bindscrolltolower="lower"` 1. `scroll-y="true">` 2. `<block wx:for="{ {menu}}" wx:key="">` 3. `<view class="menuList">` 4. `<view class="menu { {index==selected?'selected':''}}"` 5. `data-index="{ {index}}"` 6. `catchtap="turnMenu">{ {item.typeName}}</view>` 7. `</view>` 8. `</block>` 9. `</scroll-view>` 10. `<scroll-view class="foodList" scroll-y="true">` 11. `<view class="title">{ {menu[selected].typeName}}</view>` 12. `<block wx:for="{ {menu[selected].menuContent}}" wx:key="">` 13. `<view class="food">` 14. `<image class="img" src="{ {item.src}}"></image>` 15. `<view class="food-info">` 16. `<view class="name">{ {item.name}}</view>` 17. `<view class="sales">月售 { {item.sales}} 赞 { {item.rating}}` 18. `</view>` 19. `<view class="price">¥ { {item.price}}</view>` 20. `</view>` 21. `<view class="food-numb">` 22. `<view class="remove"` 23. `bindtap="removeFromTrolley"` 24. `hidden="{ {item.numb==0}}"` 25. `data-index="{ {index}}">-</view>` 26. `<text class="text"` 27. `hidden="{ {item.numb==0}}">{ {item.numb}}</text>` 28. `<view class="add"` 29. `bindtap="addToTrolley" data-index="{ {index}}">+</view>` 30. `</view>` 31. `</view>` 32. `</block>` 33. `</scroll-view>` 34. `<view class="footer { {cost!=0?'active':''}}">` 35. `<view class="howMuch">` 36. `<view class="img" style="background:{ {cost!=0?'#FFD161':'#E7E7E7'}};">` 37. `<image src="/pages/images/trolley.png" style="width:60rpx;height:60rpx;"></image>` 38. `</view>` 39. `<view class="cost" hidden="{ {cost==0}}">¥{ {cost}}</view>` 40. `<view class="free">免配送费</view>` 41. `</view>` 42. `<view class="pay">{ {cost!=0?'去结算':'15元起送'}}</view>` 43. `</view>` 44. `</template>` tab切换 这个界面最主要的功能就是tab切换,和点菜功能。其中tab切换其实用的还是swiper,因为swiper有一个current属性表示的是swiper当下显示的页面的序号,只需要将tab中被激活的项与swiper的页面互相绑定就可以了,具体代码如下: 1.turnPage: function (e) { 2.this.setData({ 3.currentPage: e.currentTarget.dataset.index 4.}) 5.}, 6.turnTitle: function (e) { 7.if(e.detail.source=="touch"){ //判断是否是滑动引起的界面切换 8.this.setData({ 9.currentPage: e.detail.current 10.}) 11.} 12.}, 当点击title中的项时获取当前序号,再将它赋值给current,当手指滑动swiper时触发bindchange事件,获取当前页面序号,使相应序号的title处于被选中的状态。有一个值得注意的地方是当点击title中的项时也会触发swiper的bindchange事件,但是我们只想让它在滑动swiper时触发,否则就会出现setData过于频繁的警告,所以我们需要在turnTitle中加一段判断语句,判断页面滑动的原因是否为滑动,如果不是则不执行下面的语句。 点菜功能只是数据绑定界面的更加复杂的应用,而且还有许多不妥之处,这里就不作说明了,有兴趣的朋友可以去我的GitHub看详细的代码。 总结 这次项目是本人的第一个微信小程序项目,希望能给大家提供一些参考价值,有什么问题和想说的都可以在评论区告诉我,文章和代码中诸多不妥当的地方也劳烦各位不吝言辞,多多斧正。这样才能帮助我更快的进步,感谢! 项目地址:[https://github.com/tzc123/wx\_project\_meituan][https_github.com_tzc123_wx_project_meituan] [Link 1]: http://9.cn/ [080221v9j3yyi3e2yzuary.gif]: /images/20220611/4f303df4f63845e0a299cbb9858a0e49.png [080222xf8j9qm806qtfo8f.gif]: /images/20220611/992797ab378547f580b7a01ad509c950.png [080222yfu5msux91rwo7wz.gif]: /images/20220611/6a18d0316cf74fa292bd3b12239a7143.png [080223cdimkidpe3de22ex.gif]: /images/20220611/f9cc49b3a6aa457cbc499186bdf22491.png [https_github.com_tzc123_wx_project_meituan]: https://github.com/tzc123/wx_project_meituan
还没有评论,来说两句吧...