前言
github地址:https://github.com/yexiaochai/wxdemo
這裡來說一說我們的理念,我們也學習小程式開發有一週多了,從近期的使用上來說,小程式可以作為底層,但是缺少一個框架層,這個框架層需要提供:
① 元件庫
② 更好的程式碼組織方式,也就是讓我們可以做到輕鬆的元件化開發
我們從最開始到現在,都在沿著這個方向去分解小程式學習,其實小程式本身的東西差不多了,但是我們程式碼過程中有時候卻越高越複雜,多了很多封裝,其實這所有的複雜都是為了設定一個基本的架構,一個標準的開發模式,讓後面寫業務程式碼的同學能更高效的寫程式碼,經過一年多的發展,事實上這種較為成熟的框架已經有了,比如我們正在使用的:
https://tencent.github.io/wepy/
但是,可以看到小程式基本還是原生JS,這其實是個非常好的學習整理機會,所以我這邊一步步和大家對小程式進行了拆分,期望能形成一套還能用的雛形,幫助大家理解,所以我們繼續今天的學習吧,為了降低單頁面難度,我們將首頁進行下改造。
首頁
首頁做了一點改造,變成了這個樣式了:
這裡需要三個點選時間點,因為日曆元件,我們昨天就做好了,而他這個出發日期事實上就是我們日曆元件的selecedDate,處理這塊邏輯:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<template name="searchbox"> <view class="c-row search-line" data-flag="start"> <view class="c-span3"> 出發</view> <view class="c-span9 js-start search-line-txt"> 請選擇出發地</view> </view> <view class="c-row search-line" data-flag="arrive"> <view class="c-span3"> 到達</view> <view class="c-span9 js-arrive search-line-txt"> 請選擇到達地</view> </view> <view class="c-row search-line" data-flag="arrive"> <view class="c-span3"> 出發日期</view> <view class="c-span9 js-arrive search-line-txt"> {{calendarSelectedDate || '請選擇出發日期'}} </view> </view> <view class="c-row " data-flag="arrive"> <span class="btn-primary full-width js_search_list">查詢</span> </view> </template> |
1 2 3 4 5 6 |
<view class="c-row search-line" data-flag="arrive"> <view class="c-span3"> 出發日期</view> <view class="c-span9 js-arrive search-line-txt"> {{calendarSelectedDate || '請選擇出發日期'}} </view> </view> |
點選時候我們彈出我們的日曆,這個時候我們日曆模組釋放一個事件顯示日曆:
PS:template不與頁面級別WXML共享一個作用域,所以我暫時都採用的include引入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<view class="c-row search-line" data-flag="start"> <view class="c-span3"> 出發</view> <view class="c-span9 js-start search-line-txt"> 請選擇出發地</view> </view> <view class="c-row search-line" data-flag="arrive"> <view class="c-span3"> 到達</view> <view class="c-span9 js-arrive search-line-txt"> 請選擇到達地</view> </view> <view class="c-row search-line" data-flag="arrive" ontap="showCalendar"> <view class="c-span3"> 出發日期</view> <view class="c-span9 js-arrive search-line-txt"> {{calendarSelectedDateStr}}</view> </view> <view class="c-row " data-flag="arrive"> <span class="btn-primary full-width js_search_list">查詢</span> </view> <include src="./mod/calendar.wxml" /> <include src="../../utils/abstract-page.wxml" /> |
1 2 3 4 5 6 |
<view class="c-row search-line" data-flag="arrive" ontap="showCalendar"> <view class="c-span3"> 出發日期</view> <view class="c-span9 js-arrive search-line-txt"> {{calendarSelectedDateStr}}</view> </view> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/* 事實上一個mod就只是一個物件,只不過為了方便拆分,將物件分拆成一個個的mod 一個mod對應一個wxml,但是共享外部的css,暫時如此設計 所有日曆模組的需求全部再此實現 */ const util = require('../../../utils/util.js') let selectedDate = new Date(); module.exports = { showCalendar: function () { this.setData({ isCalendarShow: '' }); }, onCalendarDayTap: function (e) { let data = e.detail; var date = new Date(data.year, data.month, data.day); console.log(date) this.setData({ calendarSelectedDate: date, calendarSelectedDateStr: util.dateUtil.format(date, 'Y年M月D日') }); }, data: { isCalendarShow: 'none', calendarDisplayMonthNum: 2, calendarDisplayTime: new Date(), calendarSelectedDate: selectedDate, calendarSelectedDateStr: util.dateUtil.format(selectedDate, 'Y年M月D日') } } |
顯然,這裡的日曆這樣擺設有點醜,我們這裡將其封裝成一個彈出層,所以我們這裡再做一個容器類元件,專門用於裝載頁面樣式用:
1 2 3 4 5 |
<view class="cm-modal " style="z-index: {{uiIndex}}; position: fixed; display: {{isShow}}; "> <slot ></slot> </view> <view class="cm-overlay" bindtap="onMaskEvent" style="z-index: {{maskzIndex}}; display: {{isShow}}" > </view> |
1 2 3 4 5 6 7 8 9 10 11 |
<ui-container bindonContainerHide="onContainerHide" is-show="{{isCalendarShow}}" > <view class="calendar-wrapper-box"> <view class="box-hd"> <text class="fl icon-back js_back "></text> <text class="fr icon-next js_next"></text> </view> <ui-calendar bindonDayTap="onCalendarDayTap" displayTime="{{calendarDisplayTime}}" selectedDate="{{calendarSelectedDate}}" displayMonthNum="{{calendarDisplayMonthNum}}" is-show="{{isCalendarShow}}"></ui-calendar> </view> </ui-container> |
但是這裡也引起了其他問題,因為引入了shadow-dom概念,我的樣式不能重用,元件內部樣式與外部是不能通訊的,但是這裡是頁面級別容器,內容的樣式肯定是來源頁面的,這裡沒什麼問題,所以我們這裡顯示的是正確的,但是我這裡想做一個出格一點的操作,我想用樣式將這裡日曆月標題換個位置:
而日曆元件和外部是不能通訊的,我們這裡該如何處理呢,我這裡想了兩個方案:
① 設定一個全域性使用的元件庫樣式,讓所有元件繼承,但是不知道這裡對效能是否有影響,因為這樣的話體積不會太小
② 小程式設計了可以傳入元件的方法,比如我們這裡的日曆元件我們可以這樣改變其樣式
1 2 3 4 5 6 7 8 9 |
.calendar-cm-month { position: absolute; top: 0; height: 90rpx; line-height: 90rpx; width: 100%; color: #00b358; text-align: center; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
Component({ externalClasses: ['ex-class'], behaviors: [ View ], properties: { displayMonthNum: { type: Number }, displayTime: { type: Date }, selectedDate: { type: Date } }, data: { weekDayArr: ['日', '一', '二', '三', '四', '五', '六'], }, attached: function () { //console.log(this) // debugger }, methods: { onDayTap: function (e) { this.triggerEvent('onDayTap', e.currentTarget.dataset) } } }) |
1 2 3 4 5 6 7 8 9 10 11 |
<ui-container bindonContainerHide="onContainerHide" is-show="{{isCalendarShow}}" > <view class="calendar-wrapper-box"> <view class="box-hd"> <text class="fl icon-back js_back "></text> <text class="fr icon-next js_next"></text> </view> <ui-calendar ex-class="calendar-cm-month" bindonDayTap="onCalendarDayTap" displayTime="{{calendarDisplayTime}}" selectedDate="{{calendarSelectedDate}}" displayMonthNum="{{calendarDisplayMonthNum}}" is-show="{{isCalendarShow}}"></ui-calendar> </view> </ui-container> |
具體各位去github上檢視,總而言之,我們的頁面變成了這個樣子了:
PS:這裡發現一個不知道是不是坑點的點,我們這裡屬性傳遞的是一個date物件,但是到了元件層之間變成了物件,不知微信底層做了什麼:
1 |
calendarDisplayTime: new Date() |
好像變成了一個空物件,這裡可能發生的情況是,經過傳遞的日期物件會被某種特殊處理,但是具體發生了什麼事情就不知道了,這個卻引起了我們不小的麻煩,這裡大概去翻開了一下原始碼:
極有可能,小程式本身就不支援date屬性的傳遞,我們的日曆元件能跑起來的原因是什麼,我這裡都有點疑惑了……
而且就算以物件方式傳遞到元件的date型別都會變成莫名其妙的東西:
1 2 3 4 |
ttt: { key: 'date', value: selectedDate }, |
這個特性有點令人抓不住頭腦了,這裡根據探查,很有可能Component將date物件傳入WXML解釋時候,自動轉為了日期字串了,所以我們這裡看上去是物件的東西其實是字串,這裡的建議是:跟元件的date傳遞,暫時全部使用字串代替,以免自我麻煩,然後我們先將之前的日曆操作全部變成字串,再為我們的前後按鈕加上事件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
module.exports = { showCalendar: function () { this.setData({ isCalendarShow: '' }); }, hideCalendar: function () { this.setData({ isCalendarShow: 'none' }); }, preMonth: function () { this.setData({ calendarDisplayTime: util.dateUtil.preMonth(this.data.calendarDisplayTime).toString() }); }, nextMonth: function () { this.setData({ calendarDisplayTime: util.dateUtil.nextMonth(this.data.calendarDisplayTime).toString() }); }, onCalendarDayTap: function (e) { let data = e.detail; var date = new Date(data.year, data.month, data.day); console.log(date) this.setData({ isCalendarShow: 'none', calendarSelectedDate: date.toString(), calendarSelectedDateStr: util.dateUtil.format(date, 'Y年M月D日') }); }, onContainerHide: function () { this.hideCalendar(); }, data: { ttt: { key: 'date', value: selectedDate }, isCalendarShow: '', calendarDisplayMonthNum: 1, calendarDisplayTime: new Date(2018, 9).toString(), calendarSelectedDate: selectedDate, calendarSelectedDateStr: util.dateUtil.format(new Date(selectedDate), 'Y年M月D日') } } |
雖然看上去噁心了一點,但是總是不會出什麼明顯的問題,忍一忍吧……日期部分基本結束了,還有些小的限制沒有做上,比如哪些時段能選,哪些不能,這塊就有待各位發現吧,我們這裡畢竟是學習,做細了很花功夫,我們接下來做出發目的地選擇部分。
資料請求
城市列表
城市列表這裡看起來需要新開一個頁面,但是我這裡想做在一個頁面中,考慮篇幅,我們使用彈出層容器元件看並且儘量削弱一些特性,幾天下來別說寫的還有些累……
這個又作為首頁的一個模組而存在:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<view style="display: {{isCityShow}}; " class="city-wrapper" > <view class="city-list"> <view class="list-name">A</view> <view class="list-item">成都</view> <view class="list-item">成都</view> <view class="list-item">成都</view> <view class="list-item">成都</view> <view class="list-item">成都</view> <view class="list-item">成都</view> </view> <view class="city-list"> <view class="list-name">A</view> <view class="list-item">成都</view> <view class="list-item">成都</view> <view class="list-item">成都</view> <view class="list-item">成都</view> <view class="list-item">成都</view> <view class="list-item">成都</view> </view> </view> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
/* 事實上一個mod就只是一個物件,只不過為了方便拆分,將物件分拆成一個個的mod 一個mod對應一個wxml,但是共享外部的css,暫時如此設計 所有日曆模組的需求全部再此實現 */ const util = require('../../../utils/util.js') let selectedDate = new Date().toString(); module.exports = { showCitylist: function (e) { let flag = e.currentTarget.dataset.flag; if(flag === 'start') { } else { } }, //用於設定城市資料 setCityData: function (data) { }, showCity: function () { this.setData({ isCityShow: '' }); }, shideCity: function () { this.setData({ isCityShow: 'none' }); }, data: { isCityShow: '' } } |
首頁呼叫程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
//獲取公共ui操作類例項 const _page = require('../../utils/abstract-page.js'); let modCalendar = require('./mod/calendar.js'); let modCity = require('./mod/city.js'); //獲取應用例項 const app = getApp() Page(_page.initPage({ data: { }, // methods: uiUtil.getPageMethods(), methods: { }, onShow: function () { global.sss = this; let scope = this; }, onLoad: function () { // this.setPageMethods(); } }, { modCalendar: modCalendar, modCity: modCity })) |
這裡我們開始有資料請求模組了,小程式使用這個介面請求資料,這裡比較尷尬的是他要設定域名白名單:
1 |
wx.request(OBJECT) |
而我們使用的是測試賬號沒有可以設定的地方,所以我們還是去申請個小程式賬號吧…配置成功,我們繼續程式碼:
可以看到資料請求已經回來了,但是我們一般來說一個介面不止會用於一個地方,每次重新寫好像有些費事,加之我這裡想將重複的請求快取起來,所以我們這裡封裝一套資料訪問層出來
資料快取(持久層)
之前在瀏覽器中,我們一般使用localstorage儲存一些不太更改的資料,微信裡面提供了介面處理這一切:
1 |
wx.setStorage(OBJECT) |
我們這裡需要對其進行簡單封裝,便與後面更好的使用,一般來說有快取就一定要有過期,所以我們動態給每個快取物件增加一個過期時間:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
class Store { constructor(opts) { if(typeof opts === 'string') this.key = opts; else Object.assign(this, opts); //如果沒有傳過期時間,則預設30分鐘 if(!this.lifeTime) this.lifeTime = 1; //本地快取用以存放所有localstorage鍵值與過期日期的對映 this._keyCache = 'SYSTEM_KEY_TIMEOUT_MAP'; } //獲取過期時間,單位為毫秒 _getDeadline() { return this.lifeTime * 60 * 1000; } //獲取一個資料快取物件,存可以非同步,獲取我同步即可 get(sign){ let key = this.key; let now = new Date().getTime(); var data = wx.getStorageSync(key); if(!data) return null; data = JSON.parse(data); //資料過期 if (data.deadLine < now) { this.removeOverdueCache(); return null; } if(data.sign) { if(sign === data.sign) return data.data; else return null; } return null; } /*產出頁面元件需要的引數 sign 為格式化後的請求引數,用於同一請求不同引數時候返回新資料,比如列表為北京的城市,後切換為上海,會判斷tag不同而更新快取資料,tag相當於簽名 每一鍵值只會快取一條資訊 */ set(data, sign) { let timeout = new Date(); let time = timeout.setTime(timeout.getTime() + this._getDeadline()); this._saveData(data, time, sign); } _saveData(data, time, sign) { let key = this.key; let entity = { deadLine: time, data: data, sign: sign }; let scope = this; wx.setStorage({ key: key, data: JSON.stringify(entity), success: function () { //每次真實存入前,需要往系統中儲存一個清單 scope._saveSysList(key, entity.deadLine); } }); } _saveSysList(key, timeout) { if (!key || !timeout || timeout < new Date().getTime()) return; let keyCache = this._keyCache; wx.getStorage({ key: keyCache, complete: function (data) { let oldData = {}; if(data.data) oldData = JSON.parse(data.data); oldData[key] = timeout; wx.setStorage({ key: keyCache, data: JSON.stringify(oldData) }); } }); } //刪除過期快取 removeOverdueCache() { let now = new Date().getTime(); let keyCache = this._keyCache; wx.getStorage({ key: keyCache, success: function (data) { if(data && data.data) data = JSON.parse(data.data); for(let k in data) { if(data[k] < now) { delete data[k]; wx.removeStorage({key: k, success: function(){}}); } } wx.setStorage({ key: keyCache, data: JSON.stringify(data) }); } }); } } module.exports = Store |
這個類的使用也非常簡單,這裡舉個例子:
1 2 3 4 |
sss = new global.Store({key: 'qqq', lifeTime: 1}) sss.set({a: 1}, 2) sss.get()//因為沒有祕鑰會是null sss.get(2)//sss.get(2) |
這個時候我們開始寫我們資料請求的類:
首先還是實現了一個抽象類和一個業務基類,然後開始在業務層請求資料:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
class Model { constructor() { this.url = ''; this.param = {}; this.validates = []; } pushValidates(handler) { if (typeof handler === 'function') { this.validates.push(handler); } } setParam(key, val) { if (typeof key === 'object') { Object.assign(this.param, key); } else { this.param[key] = val; } } //<a href='http://www.jobbole.com/members/wx610506454'>@override</a> buildurl() { return this.url; } onDataSuccess() { } //執行資料請求邏輯 execute(onComplete) { let scope = this; let _success = function(data) { let _data = data; if (typeof data == 'string') _data = JSON.parse(data); // @description 開發者可以傳入一組驗證方法進行驗證 for (let i = 0, len = scope.validates.length; i < len; i++) { if (!scope.validates[i](data)) { // @description 如果一個驗證不通過就返回 if (typeof onError === 'function') { return onError.call(scope || this, _data, data); } else { return false; } } } // @description 對獲取的資料做欄位對映 let datamodel = typeof scope.dataformat === 'function' ? scope.dataformat(_data) : _data; if (scope.onDataSuccess) scope.onDataSuccess.call(scope, datamodel, data); if (typeof onComplete === 'function') { onComplete.call(scope, datamodel, data); } }; this._sendRequest(_success); } //刪除過期快取 _sendRequest(callback) { let url = this.buildurl(); wx.request({ url: this.buildurl(), data: this.param, success: function success(data) { callback && callback(data); } }); } } module.exports = Model |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
let Model = require('./abstract-model.js'); class DemoModel extends Model { constructor() { super(); let scope = this; this.domain = 'https://apikuai.baidu.com'; this.param = { head: { version: '1.0.1', ct: 'ios' } }; //如果需要快取,可以在此設定快取物件 this.cacheData = null; this.pushValidates(function(data) { return scope._baseDataValidate(data); }); } //首輪處理返回資料,檢查錯誤碼做統一驗證處理 _baseDataValidate(data) { if (typeof data === 'string') data = JSON.parse(data); if (data.data) data = data.data; if (data.errno === 0) return true; return false; } dataformat(data) { if (typeof data === 'string') data = JSON.parse(data); if (data.data) data = data.data; if (data.data) data = data.data; return data; } buildurl() { return this.domain + this.url; } getSign() { let param = this.getParam() || {}; return JSON.stringify(param); } onDataSuccess(fdata, data) { if (this.cacheData && this.cacheData.set) this.cacheData.set(fdata, this.getSign()); } //如果有快取直接讀取快取,沒有才請求 execute(onComplete, ajaxOnly) { let data = null; if (!ajaxOnly && this.cacheData && this.cacheData.get) { data = this.cacheData.get(this.getSign()); if (data) { onComplete(data); return; } } super.execute(onComplete); } } class CityModel extends DemoModel { constructor() { super(); this.url = '/city/getstartcitys'; } } module.exports = { cityModel: new CityModel } 業務基類 |
接下來是實際呼叫程式碼:
1 2 3 4 5 6 7 8 |
let model = models.cityModel; model.setParam({ type: 1 }); model.execute(function(data) { console.log(data); debugger; }); |
資料便請求結束了,有了這個類我們可以做非常多的工作,比如:
① 前端設定統一的錯誤碼處理邏輯
② 前端打點,統計所有的介面響應狀態
③ 每次請求相同引數做資料快取
④ 這個對於錯誤處理很關鍵,一般來說前端出錯很大可能都是後端資料介面欄位有變化,而這種錯誤是比較難尋找的,如果我這裡做一個統一的收口,每次資料返回記錄所有的返回欄位的標誌上報呢,就以這個城市資料為例,我們可以這樣做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class CityModel extends DemoModel { constructor() { super(); this.url = '/city/getstartcitys'; } //每次資料訪問成功,錯誤碼為0時皆會執行這個回撥 onDataSuccess(fdata, data) { super.onDataSuccess(fdata, data); //開始執行自我邏輯 let o = { _indate: new Date().getTime() }; for(let k in fdata) { o[k] = typeof fdata[k]; } //執行資料上報邏輯 console.log(JSON.stringify(o)); } } |
這裡就會輸出以下資訊:
1 |
{"_indate":1533436847778,"cities":"object","hots":"object","total":"number","page":"string"} |
如果對資料要求非常嚴苛,對某些介面做到欄位層面的驗證,那麼加一個Validates驗證即可,這樣對介面的控制會最大化,就算哪次出問題,也能很好從資料分析系統之中可以檢視到問題所在,如果我現在想要一個更為具體的功能呢?我想要首次請求一個介面時便將其資料記錄下來,第二次便不再請求呢,這個時候我們之前設計的資料持久層便派上了用處:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
let Store = require('./abstract-store.js'); class CityStore extends Store { constructor() { super(); this.key = 'DEMO_CITYLIST'; //30分鐘過期時間 this.lifeTime = 30; } } module.exports = { cityStore: new CityStore } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class CityModel extends DemoModel { constructor() { super(); this.url = '/city/getstartcitys'; this.cacheData = Stores.cityStore; } //每次資料訪問成功,錯誤碼為0時皆會執行這個回撥 onDataSuccess(fdata, data) { super.onDataSuccess(fdata, data); //開始執行自我邏輯 let o = { _indate: new Date().getTime() }; for(let k in fdata) { o[k] = typeof fdata[k]; } //執行資料上報邏輯 console.log(JSON.stringify(o)); } } |
這個時候第二次請求時候便會直接讀取快取了
接下來便可以回到我們的頁面渲染邏輯了,這個時候就變得非常簡單了:
1 2 3 4 5 6 7 8 9 10 11 12 |
<view style="display: {{isCityShow}}; " class="city-wrapper"> <block wx:for="{{cityData}}" wx:key="k"> <view class="city-list"> <block wx:for="{{item}}" wx:key="kk" wx:for-index="key" wx:for-item="value"> <view class="list-name">{{key}}</view> <block wx:for="{{value}}" wx:key="kkk" wx:for-index="i" wx:for-item="v"> <view class="list-item" data-cnname="{{v.name}}" data-id="{{v.regionid}}">{{v.cnname}}</view> </block> </block> </view> </block> </view> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
//用於設定城市資料 setCityData: function(data) { data = data.cities; let citys = {}, sortCitys = []; let k, gname, name, i, tmp = {}, index; //首先處理每個name生成唯一K for (k in data) { name = data[k].name; if (!name) { continue; } gname = name[0].toUpperCase(); if (!citys[gname]) citys[gname] = []; citys[gname].push(data[k]); } for (i = 65; i < 91; i++) { tmp = {}; tmp[String.fromCharCode(i)] = []; sortCitys.push(tmp); } for (k in citys) { index = k.charCodeAt() - 65; tmp = {}; tmp[k] = citys[k]; sortCitys[index] = tmp; } this.setData({ cityData: sortCitys, isCityShow: '' }); }, |
然後我們這裡為元件繫結事件等就比較簡單了,大家可以自己看github,於是我們首頁的功能便完成了:
經過一個多星期的學習,我們慢慢的完成了我們的首頁,好像也就幾個元素,但是後面的一切卻不簡單啊,我們明天繼續完成list頁面邏輯,便開始總結小程式開發