初(chu)識小程序,為它的(de)小巧玲瓏所吸引,不(bu)由得(de)心血來(lai)潮。這不(bu)正是(shi)用戶所需要的(de)嗎?既方便快捷,又(you)不(bu)占(zhan)手機內存。所以(yi)我下(xia)定決(jue)心一(yi)定要做出一(yi)個自(zi)(zi)己的(de)小程序,然(ran)(ran)后賺錢(qian)(qian)、賺錢(qian)(qian)、賺錢(qian)(qian)...當(dang)然(ran)(ran)現在只是(shi)學習(xi)階段,所以(yi)先仿(fang)一(yi)個高(gao)端(duan)產品(pin)來(lai)挑戰自(zi)(zi)我吧(ba)。說到高(gao)端(duan),自(zi)(zi)然(ran)(ran)然(ran)(ran)而的(de)就想到了美團。之后噼里啪啦一(yi)頓忙乎(hu),終于做出了一(yi)點樣子(zi)來(lai),希(xi)望能為同為小白(bai)的(de)同學們(men)提供一(yi)點幫助和參考,現在我們(men)進入正題。
開發工具
微信web開發者(zhe)工具(ju): 官網(wang)(wang)就可以下(xia)(xia)載,相信大家(jia)早就安裝(zhuang)好了吧(ba)。 小程序(xu) API: 官網(wang)(wang)提(ti)供的(de)文檔,不懂得地方多看(kan)兩(liang)遍基本上就可以解決(jue)了。 Easy Mock: 一個(ge)能夠提(ti)供虛擬數(shu)據接口的(de)網(wang)(wang)站(zhan),在(zai)前端(duan)獨自(zi)開發的(de)情況下(xia)(xia),實(shi)在(zai)是再(zai)好不過(guo)的(de)工具(ju)了。 功能
已經(jing)實現的功能:
主界(jie)(jie)面(mian)(mian) 訂單界(jie)(jie)面(mian)(mian) 用戶界(jie)(jie)面(mian)(mian) 點菜(cai)界(jie)(jie)面(mian)(mian) 定位界(jie)(jie)面(mian)(mian) 未實現(xian)的(de)功(gong)能:
數(shu)都(dou)數(shu)不(bu)清,畢竟大企業的(de)產品,不(bu)是(shi)說模仿就(jiu)模仿的(de),所以(yi)只實現了一(yi)些(xie)主要(yao)的(de)功能(neng),和一(yi)些(xie)能(neng)力之內的(de)功能(neng)... 項目(mu)啟動
創建界面
"pages":[
"pages/home/home",
"pages/menu/menu",
"pages/location/location",
"pages/my/my",
"pages/order/order"
.],
只(zhi)要(yao)編(bian)輯(ji)app.js中的(de)(de)pages屬性(xing),就(jiu)(jiu)會(hui)在(zai)項目目錄下的(de)(de)pages文(wen)件夾里自動生成一個(ge)文(wen)件夾,里面包擴了.wxml 、 .wxss 、 .json 、 .js這樣四(si)個(ge)文(wen)件。wxml就(jiu)(jiu)是界(jie)(jie)面結構文(wen)件, .wxss就(jiu)(jiu)是樣式文(wen)件, .js是用(yong)來存(cun)放js代碼(ma)并實現界(jie)(jie)面邏輯(ji)的(de)(de)地方,至于(yu) .json就(jiu)(jiu)是用(yong)來配置(zhi)頁(ye)面屬性(xing)的(de)(de)地方,如:修(xiu)改標題欄的(de)(de)顏色,和文(wen)字。
配(pei)置標(biao)題欄(lan)的樣式
"window":{
"navigationBarTitleText": "美團外賣+",
"navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#FFC640"
},
同樣是在(zai)app.json中配置,其他頁面的(de)標題欄(lan)都以此為例。
添加底欄
"tabBar": {
"color": "#272636",
"selectedColor": "#FFD161",
"backgroundColor": "#fff",
"borderStyle": "#a8a8a8",
"list": [
{
"pagePath": "pages/home/home",
"iconPath": "pages/images/home.png",
"selectedIconPath": "pages/images/home-selected.png",
"color":"white",
"text": "首頁"
},
{
"pagePath": "pages/order/order",
"iconPath": "pages/images/order.png",
"selectedIconPath": "pages/images/order-selected.png",
"text": "訂單"
},
{
"pagePath": "pages/my/my",
"iconPath": "pages/images/my.png",
"selectedIconPath": "pages/images/my-selected.png",
"text": "我的"
}
]
}
在(zai)app.json中(zhong)編寫以上代碼,這(zhe)是(shi)小程(cheng)序自(zi)帶的功(gong)能,只需要照(zhao)搬照(zhao)抄就可以了,極其方便,效果如下:

image 數據請求(qiu)
/**
* 生命周期函數--監聽頁面顯示
*/
onShow: function () {
var that = this;
wx.request({
url: "//www.easy-mock.com/mock/596257bc9adc231f357c4664/restaurant/info",//easy-mock生成的虛擬數據接口鏈接
method: "GET",
success: function (res) {//成功得到數據,對數據進行處理
that.setData({//將數據發送到data中
restaurant: res.data.data.restaurant,
location: wx.getStorageSync('location')
})
}
});
},
data是(shi)每(mei)個頁(ye)面(mian).js文件中(zhong)(zhong)都存在的(de)一個鍵(jian),用(yong)來儲存本頁(ye)面(mian)需要用(yong)到的(de)數(shu)據。具體使(shi)用(yong),可在wxml文件中(zhong)(zhong)用(yong){{'data中(zhong)(zhong)的(de)鍵(jian)名'}}的(de)形式調用(yong)數(shu)據。 虛擬數(shu)據大(da)致如(ru)下:
{
"success": true,
"data": {
"restaurant": [{
"name": "御膳房",
"src": "//i2.kiimg.com/601998/a955867016875a41.jpg",
"star": 4.5,
"sales": 641,
"initial_price": 0,
"distribution_price": 0,
"distance": "156m",
"time": 33
}, {
"name": "韓式炸雞啤酒屋",
"star": 4.5,
"sales": 731,
"src": "//i4.piimg.com/601998/9ce47f2f19d7717d.jpg",
"initial_price": 15,
"distribution_price": 0,
"distance": "1.3km",
"time": 52
},{
//略去
},{
//略去
},{
//...
}]
}
}
主界面 效(xiao)果圖:

image swiper控件應用(yong)
首先(xian)是兩頁標簽的(de)滑(hua)動切換,這里使(shi)用的(de)是swiper,它是一(yi)款(kuan)小程序(xu)自帶的(de)滑(hua)塊組件,使(shi)用掌握起來非常簡單,具體代碼如下:
<swiper class="categoryList" indicator-dots="true"
indicator-color="rgba(228,228,228,1)"
indicator-active-color="#FECA49">
<block wx:for="{{categoryList}}" wx:key="">
<swiper-item>
<block wx:for="{{item}}" wx:key="">
<view class="category-info">
<image src="{{item.src}}"
class="category-image"></image>
<view class="category-text">{{item.name}}</view>
</view>
</block>
</swiper-item>
</block>
</swiper>
swiper標簽(qian)就是(shi)滑(hua)塊(kuai)組(zu)件的(de)主體,表(biao)示可以滑(hua)動的(de)區(qu)域,其中(zhong)(zhong)indicator-dots屬性(xing)是(shi)設置(zhi)設置(zhi)點是(shi)否顯(xian)示。接下來swiper-item標簽(qian)在(zai)swiper之中(zhong)(zhong)表(biao)示的(de)是(shi)每一個(ge)用(yong)(yong)來作為(wei)滑(hua)動的(de)頁面。這(zhe)里(li)用(yong)(yong)包裹著swiper-item表(biao)示的(de)是(shi)使用(yong)(yong)categoryList對(dui)象數(shu)組(zu)中(zhong)(zhong)數(shu)據來循環(huan)渲(xuan)染(ran)swiper-item,swiper-item的(de)數(shu)量取決于categoryList中(zhong)(zhong)有(you)多(duo)少組(zu)數(shu)據。之后在(zai)swiper-item中(zhong)(zhong)的(de)block標簽(qian)表(biao)示的(de)是(shi)在(zai)一個(ge)頁面中(zhong)(zhong)用(yong)(yong)categoryList.item中(zhong)(zhong)的(de)數(shu)據循環(huan)渲(xuan)染(ran)多(duo)個(ge)類似的(de)標簽(qian),這(zhe)些標簽(qian)就是(shi)效果圖中(zhong)(zhong)的(de)類別(bie)項,總共兩頁,每頁八(ba)個(ge)。這(zhe)就是(shi)swiper和循環(huan)渲(xuan)染(ran)的(de)一些基本用(yong)(yong)法。
彈出層的實現
<view class="mask"
hidden="{{mask2Hidden}}" bindtap="mask2Cancel">
<template is="sort_list" data="{{selected,sortSelected}}"/>
<scroll-view class="filterList" scroll-y="true" >
<view class="filterList-characteristic-title">商家特色</view>
<view class="filterList-characteristic-items">
<block wx:for="{{characteristicList}}" wx:key="">
<view class="filterList-characteristic-item {{characteristicSelected[index]==true?'characteristic-selected':''}}"
catchtap="characteristicSelected" data-index="{{index}}">{{item.text}}</view>
</block>
</view>
<view class="filterList-discount-title">優惠活動(單選)</view>
<view class="filterList-discount-items">
<block wx:for="{{discountList}}" wx:key="">
<view class="filterList-discount-item {{discountSelected==index?'discount-selected':''}}"
catchtap="discountSelected" data-index="{{index}}">
<text class="filterList-discount-item-icon"
style="background:{{item.iconColor}}">{{item.icon}}</text>
{{item.text}}</view>
</block>
</view>
</scroll-view>
<view class="filterList-footer">
<view class="filterList-footer-delect"
catchtap="clearSelectedNumb">清除篩選</view>
<view class="filterList-footer-finish" bindtap="finish">完成
<view class="filterList-footer-finish-number" hidden="{{selectedNumb==0}}">{{selectedNumb}}
</view>
</view>
</view>
</view>
最(zui)外層的(de)(de)(de)mask類的(de)(de)(de)view就是(shi)(shi)一(yi)個遮(zhe)罩層,用來(lai)(lai)覆蓋之前(qian)的(de)(de)(de)界面形成遮(zhe)罩的(de)(de)(de)效果,并在上面顯示新的(de)(de)(de)界面也就是(shi)(shi)彈出層。以上的(de)(de)(de)代碼就是(shi)(shi)效果圖(tu)中(zhong)點(dian)(dian)擊(ji)篩選(xuan)按鈕所呈現出來(lai)(lai)的(de)(de)(de)內容(rong)(rong)了(le)。其中(zhong)bindtap屬性就是(shi)(shi)點(dian)(dian)擊(ji)事(shi)件的(de)(de)(de)綁定(ding)了(le),具體的(de)(de)(de)點(dian)(dian)擊(ji)事(shi)件需(xu)要在.js文件中(zhong)設置。值得一(yi)提的(de)(de)(de)是(shi)(shi),bindtap事(shi)件是(shi)(shi)會把當前(qian)標簽受(shou)到的(de)(de)(de)點(dian)(dian)擊(ji)冒泡給它的(de)(de)(de)父容(rong)(rong)器(qi),這就相當與同(tong)時點(dian)(dian)擊(ji)了(le)他(ta)的(de)(de)(de)父容(rong)(rong)器(qi),如果想阻止冒泡的(de)(de)(de)話就需(xu)要使用catchtap。
定位界面
先上效果圖:

image
頁面結構:
<view class="header">
<view class="search-input">
<input placeholder="請輸入收貨地址"
bindinput="input"></input>
</view>
<view class="search-btn">搜索</view>
</view>
<view class="result-container" hidden="{{hidden}}">
<scroll-view scroll-y="true"class="search-result-list" hidden="{{hidden}}">
<block wx:for="{{locationList}}" wx:key="">
<view class="search-result" bindtap="onTap" data-key="{{item.address}}">{{item.name}}
<view class="search-result-desc">{{item.address}}</view>
</view>
</block>
</scroll-view>
</view>
<view class="getLocation"
bindtap="getLocation">點擊定位當前位置</view>
<view class="addLocation">新增收貨地址
<view class="addLocation-icon">+</view>
</view>
<view class="myLocation">我的收貨地址</view>
<view class="LocatonInfo"></view>
<view class="userTel"></view>
這個界面主要(yao)涉及到的就是彈出層(ceng)和百度地(di)圖API的調(diao)用,調(diao)用方法可以查看百度地(di)圖API,具體點擊事件代碼如下:
getLocation: function () { wx.getLocation({ type: 'gcj02', success: function (res) { var latitude = res.latitude var longitude = res.longitude wx.request({ url: '//api.map.baidu.com/geocoder/v2/?ak=btsVVWf0TM1zUBEbzFz6QqWF&coordtype=gcj02ll&location=' + latitude + ',' + longitude + '&output=json&pois=0', method: "get", success: function (res) { console.log(res.data.result.formatted_address) wx.setStorageSync('location', res.data.result.formatted_address.substr(res.data.result.formatted_address.indexOf('市') + 1, 10)) } }) } }) wx.switchTab({ url: '/pages/home/home' }) }, input: function (e){ if(e.detail.value){ this.setData({ hidden: false })this.search(e.detail.value); }else{ this.setData({ hidden: true }) } }, search: function (text){ var that = this; wx.request({ url: '//api.map.baidu.com/place/v2/search?query=' + text +'&page_size=20&page_num=0&scope=2®ion=南昌&output=json&ak=btsVVWf0TM1zUBEbzFz6QqWF', success: function(res){ console.log(res); that.setData({ locationList:res.data.results }) } }) },
點(dian)菜界面(mian) 效果(guo)圖如下:

image
頁面結構如(ru)下:
<import src = "../common/orderPage.wxml"/>
<import src = "../common/commentPage.wxml"/>
<view class="container" disable-scroll="true">
<view class="header">
<block wx:for="{{swiperTitle}}" wx:key="">
<view class="title {{index==currentPage?'selected':''}}" data-index="{{index}}
bindtap="turnPage">{{item.text}}</view>
</block>
</view>
<swiper class="swiper" current="{{currentPage}}
bindchange="turnTitle">
<swiper-item id="orderPage">
<template is="orderPage" data="{{menu,selected,howMuch,cost,pullBar}}"/>
</swiper-item>
<swiper-item id="commentPage">
<template is="commentPage" data="{{categoryList}}"/>
</swiper-item>
<swiper-item id="restaurantPage"></swiper-item>
</swiper>
</view>
菜單頁面如下:<template name="orderPage">
2.<scroll-view class="orderPage-sideBar"
3.bindscrolltolower="lower"
tab切換
這(zhe)個界面(mian)最(zui)主要的(de)(de)功能(neng)就是tab切(qie)換,和點菜功能(neng)。其中tab切(qie)換其實用的(de)(de)還是swiper,因(yin)為swiper有一個current屬性表(biao)示(shi)的(de)(de)是swiper當下顯示(shi)的(de)(de)頁面(mian)的(de)(de)序號,只需(xu)要將tab中被激活的(de)(de)項與swiper的(de)(de)頁面(mian)互相(xiang)綁(bang)定就可以了(le),具體代碼如下:
turnPage: function (e) {
this.setData({
currentPage: e.currentTarget.dataset.index
})
},
turnTitle: function (e) {
if(e.detail.source=="touch"){//判斷是否是滑動引起的界面切換
this.setData({
currentPage: e.detail.current
})
}
},
當點(dian)(dian)擊(ji)title中(zhong)(zhong)的(de)(de)(de)(de)項(xiang)時獲取(qu)當前序號,再將它賦值給(gei)current,當手指滑動swiper時觸發bindchange事件(jian),獲取(qu)當前頁(ye)面序號,使相應(ying)序號的(de)(de)(de)(de)title處于被選中(zhong)(zhong)的(de)(de)(de)(de)狀態。有一(yi)(yi)個值得注意的(de)(de)(de)(de)地(di)方是當點(dian)(dian)擊(ji)title中(zhong)(zhong)的(de)(de)(de)(de)項(xiang)時也會觸發swiper的(de)(de)(de)(de)bindchange事件(jian),但(dan)是我(wo)們只(zhi)想讓它在(zai)滑動swiper時觸發,否則(ze)就會出現setData過(guo)于頻繁的(de)(de)(de)(de)警告(gao),所以我(wo)們需要(yao)在(zai)turnTitle中(zhong)(zhong)加一(yi)(yi)段(duan)判斷語句,判斷頁(ye)面滑動的(de)(de)(de)(de)原因是否為滑動,如果不(bu)(bu)是則(ze)不(bu)(bu)執行下面的(de)(de)(de)(de)語句。 點(dian)(dian)菜功能只(zhi)是數據綁定界面的(de)(de)(de)(de)更加復雜的(de)(de)(de)(de)應(ying)用,而且還有許多(duo)不(bu)(bu)妥之處,這里就不(bu)(bu)作說(shuo)明了,有興趣(qu)的(de)(de)(de)(de)朋友可(ke)以去我(wo)的(de)(de)(de)(de)GitHub看詳細(xi)的(de)(de)(de)(de)代碼。
總結
這次項目是(shi)本人的(de)第一個微信小程序項目,希望能(neng)給(gei)大家提供一些參考價值,有什么問題和(he)想說的(de)都可(ke)以在評論區告訴我,文章和(he)代碼中諸多(duo)不妥(tuo)當的(de)地方也(ye)勞(lao)煩各位不吝(lin)言辭,多(duo)多(duo)斧正。這樣才(cai)能(neng)幫助我更快的(de)進步(bu),感謝!
項目地址://github.com/tzc123/wx_project_meituan