作者:葉小釵?
https://www.cnblogs.com/yexiaochai/p/9419368.html
前言
接上文:
微信小程序開發(fā)(5):日歷組件的實(shí)現(xiàn)
github地址:https://github.com/yexiaochai/wxdemo
這里來說一說我們的理念茬缩,我們也學(xué)習(xí)小程序開發(fā)有一周多了土浸,從近期的使用上來說慎宾,小程序可以作為底層窟扑,但是缺少一個(gè)框架層集索,這個(gè)框架層需要提供:
① 組件庫
② 更好的代碼組織方式鸭轮,也就是讓我們可以做到輕松的組件化開發(fā)
我們從最開始到現(xiàn)在羡棵,都在沿著這個(gè)方向去分解小程序?qū)W習(xí)她紫,其實(shí)小程序本身的東西差不多了沉御,但是我們代碼過程中有時(shí)候卻越高越復(fù)雜屿讽,多了很多封裝,其實(shí)這所有的復(fù)雜都是為了設(shè)置一個(gè)基本的架構(gòu)吠裆,一個(gè)標(biāo)準(zhǔn)的開發(fā)模式伐谈,讓后面寫業(yè)務(wù)代碼的同學(xué)能更高效的寫代碼,經(jīng)過一年多的發(fā)展试疙,事實(shí)上這種較為成熟的框架已經(jīng)有了诵棵,比如我們正在使用的:
https://tencent.github.io/wepy/
但是,可以看到小程序基本還是原生JS祝旷,這其實(shí)是個(gè)非常好的學(xué)習(xí)整理機(jī)會(huì)履澳,所以我這邊一步步和大家對小程序進(jìn)行了拆分,期望能形成一套還能用的雛形怀跛,幫助大家理解距贷,所以我們繼續(xù)今天的學(xué)習(xí)吧,為了降低單頁面難度吻谋,我們將首頁進(jìn)行下改造忠蝗。
首頁
首頁做了一點(diǎn)改造,變成了這個(gè)樣式了:
這里需要三個(gè)點(diǎn)擊時(shí)間點(diǎn)滨溉,因?yàn)槿諝v組件什湘,我們昨天就做好了,而他這個(gè)出發(fā)日期事實(shí)上就是我們?nèi)諝v組件的selecedDate晦攒,處理這塊邏輯:
<template name="searchbox">
??<view class="c-row search-line" data-flag="start">
????<view class="c-span3">
??????出發(fā)</view>
????<view class="c-span9 js-start search-line-txt">
??????請選擇出發(fā)地</view>
??</view>
??<view class="c-row search-line" data-flag="arrive">
????<view class="c-span3">
??????到達(dá)</view>
????<view class="c-span9 js-arrive search-line-txt">
??????請選擇到達(dá)地</view>
??</view>
??<view class="c-row search-line" data-flag="arrive">
????<view class="c-span3">
??????出發(fā)日期</view>
????<view class="c-span9 js-arrive search-line-txt">
??????{{calendarSelectedDate || '請選擇出發(fā)日期'}} </view>
??</view>
??<view class="c-row " data-flag="arrive">
????<span class="btn-primary full-width js_search_list">查詢</span>
??</view>
</template>
<view class="c-row search-line" data-flag="arrive">
??<view class="c-span3">
????出發(fā)日期</view>
??<view class="c-span9 js-arrive search-line-txt">
????{{calendarSelectedDate || '請選擇出發(fā)日期'}} </view>
</view>
點(diǎn)擊時(shí)候我們彈出我們的日歷闽撤,這個(gè)時(shí)候我們?nèi)諝v模塊釋放一個(gè)事件顯示日歷:
PS:template不與頁面級(jí)別WXML共享一個(gè)作用域,所以我暫時(shí)都采用的include引入
<view class="c-row search-line" data-flag="start">
??<view class="c-span3">
????出發(fā)</view>
??<view class="c-span9 js-start search-line-txt">
????請選擇出發(fā)地</view>
</view>
<view class="c-row search-line" data-flag="arrive">
??<view class="c-span3">
????到達(dá)</view>
??<view class="c-span9 js-arrive search-line-txt">
????請選擇到達(dá)地</view>
</view>
<view class="c-row search-line" data-flag="arrive" ontap="showCalendar">
??<view class="c-span3">
????出發(fā)日期</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" />
<view class="c-row search-line" data-flag="arrive" ontap="showCalendar">
??<view class="c-span3">
????出發(fā)日期</view>
??<view class="c-span9 js-arrive search-line-txt">
????{{calendarSelectedDateStr}}</view>
</view>
/*
事實(shí)上一個(gè)mod就只是一個(gè)對象,只不過為了方便拆分,將對象分拆成一個(gè)個(gè)的mod
一個(gè)mod對應(yīng)一個(gè)wxml,但是共享外部的css,暫時(shí)如此設(shè)計(jì)
所有日歷模塊的需求全部再此實(shí)現(xiàn)
*/
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日')
??}
}
顯然脯颜,這里的日歷這樣擺設(shè)有點(diǎn)丑哟旗,我們這里將其封裝成一個(gè)彈出層,所以我們這里再做一個(gè)容器類組件,專門用于裝載頁面樣式用:
<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>
<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>
但是這里也引起了其他問題闸餐,因?yàn)橐肓藄hadow-dom概念饱亮,我的樣式不能重用,組件內(nèi)部樣式與外部是不能通信的舍沙,但是這里是頁面級(jí)別容器近上,內(nèi)容的樣式肯定是來源頁面的,這里沒什么問題拂铡,所以我們這里顯示的是正確的壹无,但是我這里想做一個(gè)出格一點(diǎn)的操作,我想用樣式將這里日歷月標(biāo)題換個(gè)位置:
而日歷組件和外部是不能通信的感帅,我們這里該如何處理呢斗锭,我這里想了兩個(gè)方案:
① 設(shè)置一個(gè)全局使用的組件庫樣式,讓所有組件繼承失球,但是不知道這里對性能是否有影響岖是,因?yàn)檫@樣的話體積不會(huì)太小
② 小程序設(shè)計(jì)了可以傳入組件的方法,比如我們這里的日歷組件我們可以這樣改變其樣式
.calendar-cm-month {
????position: absolute;
????top: 0;
????height: 90rpx;
????line-height: 90rpx;
????width: 100%;
????color: #00b358;
????text-align: center;
}
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)
????}
??}
})
<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上查看实苞,總而言之豺撑,我們的頁面變成了這個(gè)樣子了:
PS:這里發(fā)現(xiàn)一個(gè)不知道是不是坑點(diǎn)的點(diǎn),我們這里屬性傳遞的是一個(gè)date對象硬梁,但是到了組件層之間變成了對象前硫,不知微信底層做了什么:
calendarDisplayTime: new Date()
好像變成了一個(gè)空對象,這里可能發(fā)生的情況是荧止,經(jīng)過傳遞的日期對象會(huì)被某種特殊處理屹电,但是具體發(fā)生了什么事情就不知道了,這個(gè)卻引起了我們不小的麻煩跃巡,這里大概去翻開了一下源碼:
極有可能危号,小程序本身就不支持date屬性的傳遞,我們的日歷組件能跑起來的原因是什么素邪,我這里都有點(diǎn)疑惑了……
而且就算以對象方式傳遞到組件的date類型都會(huì)變成莫名其妙的東西:
ttt: {
?? key: 'date',
?? value: selectedDate
},
這個(gè)特性有點(diǎn)令人抓不住頭腦了外莲,這里根據(jù)探查,很有可能Component將date對象傳入WXML解釋時(shí)候兔朦,自動(dòng)轉(zhuǎn)為了日期字符串了偷线,所以我們這里看上去是對象的東西其實(shí)是字符串,這里的建議是:跟組件的date傳遞沽甥,暫時(shí)全部使用字符串代替声邦,以免自我麻煩,然后我們先將之前的日歷操作全部變成字符串摆舟,再為我們的前后按鈕加上事件:
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日')
??}
}
雖然看上去惡心了一點(diǎn)亥曹,但是總是不會(huì)出什么明顯的問題邓了,忍一忍吧……日期部分基本結(jié)束了,還有些小的限制沒有做上媳瞪,比如哪些時(shí)段能選骗炉,哪些不能,這塊就有待各位發(fā)現(xiàn)吧蛇受,我們這里畢竟是學(xué)習(xí)句葵,做細(xì)了很花功夫,我們接下來做出發(fā)目的地選擇部分兢仰。
數(shù)據(jù)請求
城市列表
城市列表這里看起來需要新開一個(gè)頁面笼呆,但是我這里想做在一個(gè)頁面中,考慮篇幅旨别,我們使用彈出層容器組件看并且盡量削弱一些特性,幾天下來別說寫的還有些累……
這個(gè)又作為首頁的一個(gè)模塊而存在:
<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>
/*
事實(shí)上一個(gè)mod就只是一個(gè)對象,只不過為了方便拆分,將對象分拆成一個(gè)個(gè)的mod
一個(gè)mod對應(yīng)一個(gè)wxml,但是共享外部的css,暫時(shí)如此設(shè)計(jì)
所有日歷模塊的需求全部再此實(shí)現(xiàn)
*/
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 {
????}
??},
??//用于設(shè)置城市數(shù)據(jù)
??setCityData: function (data) {
??},
??showCity: function () {
??????this.setData({
????????isCityShow: ''
??????});
??},
??shideCity: function () {
????this.setData({
??????isCityShow: 'none'
????});
??},
??data: {
????isCityShow: ''
??}
}
首頁調(diào)用代碼:
//獲取公共ui操作類實(shí)例
const _page = require('../../utils/abstract-page.js');
let modCalendar = require('./mod/calendar.js');
let modCity = require('./mod/city.js');
//獲取應(yīng)用實(shí)例
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
}))
這里我們開始有數(shù)據(jù)請求模塊了汗茄,小程序使用這個(gè)接口請求數(shù)據(jù)秸弛,這里比較尷尬的是他要設(shè)置域名白名單:
wx.request(OBJECT)
而我們使用的是測試賬號(hào)沒有可以設(shè)置的地方,所以我們還是去申請個(gè)小程序賬號(hào)吧…配置成功洪碳,我們繼續(xù)代碼:
可以看到數(shù)據(jù)請求已經(jīng)回來了递览,但是我們一般來說一個(gè)接口不止會(huì)用于一個(gè)地方,每次重新寫好像有些費(fèi)事瞳腌,加之我這里想將重復(fù)的請求緩存起來绞铃,所以我們這里封裝一套數(shù)據(jù)訪問層出來
數(shù)據(jù)緩存(持久層)
之前在瀏覽器中,我們一般使用localstorage存儲(chǔ)一些不太更改的數(shù)據(jù)嫂侍,微信里面提供了接口處理這一切:
wx.setStorage(OBJECT)
我們這里需要對其進(jìn)行簡單封裝儿捧,便與后面更好的使用,一般來說有緩存就一定要有過期挑宠,所以我們動(dòng)態(tài)給每個(gè)緩存對象增加一個(gè)過期時(shí)間:
class Store {
??constructor(opts) {
????if(typeof opts === 'string') this.key = opts;
????else Object.assign(this, opts);
????//如果沒有傳過期時(shí)間,則默認(rèn)30分鐘
????if(!this.lifeTime) this.lifeTime = 1;
????//本地緩存用以存放所有l(wèi)ocalstorage鍵值與過期日期的映射
????this._keyCache = 'SYSTEM_KEY_TIMEOUT_MAP';
??}
??//獲取過期時(shí)間,單位為毫秒
??_getDeadline() {
????return this.lifeTime * 60 * 1000;
??}
??//獲取一個(gè)數(shù)據(jù)緩存對象,存可以異步,獲取我同步即可
??get(sign){
????let key = this.key;
????let now = new Date().getTime();
????var data = wx.getStorageSync(key);
????if(!data) return null;
????data = JSON.parse(data);
????//數(shù)據(jù)過期
????if (data.deadLine < now) {
??????this.removeOverdueCache();
??????return null;
????}
????if(data.sign) {
??????if(sign === data.sign) return data.data;
??????else return null;
????}
????return null;
??}
??/*產(chǎn)出頁面組件需要的參數(shù)
??sign 為格式化后的請求參數(shù)菲盾,用于同一請求不同參數(shù)時(shí)候返回新數(shù)據(jù),比如列表為北京的城市各淀,后切換為上海懒鉴,會(huì)判斷tag不同而更新緩存數(shù)據(jù),tag相當(dāng)于簽名
??每一鍵值只會(huì)緩存一條信息
??*/
??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 () {
????????//每次真實(shí)存入前,需要往系統(tǒng)中存儲(chǔ)一個(gè)清單
????????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
這個(gè)類的使用也非常簡單碎浇,這里舉個(gè)例子:
sss = new global.Store({key: 'qqq', lifeTime: 1})
sss.set({a: 1}, 2)
sss.get()//因?yàn)闆]有秘鑰會(huì)是null
sss.get(2)//sss.get(2)
這個(gè)時(shí)候我們開始寫我們數(shù)據(jù)請求的類:
首先還是實(shí)現(xiàn)了一個(gè)抽象類和一個(gè)業(yè)務(wù)基類临谱,然后開始在業(yè)務(wù)層請求數(shù)據(jù):
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 >@override</a>
??buildurl() {
????return this.url;
??}
??onDataSuccess() {
??}
??//執(zhí)行數(shù)據(jù)請求邏輯
??execute(onComplete) {
????let scope = this;
????let _success = function(data) {
??????let _data = data;
??????if (typeof data == 'string') _data = JSON.parse(data);
??????// @description 開發(fā)者可以傳入一組驗(yàn)證方法進(jìn)行驗(yàn)證
??????for (let i = 0, len = scope.validates.length; i < len; i++) {
????????if (!scope.validates[i](data)) {
??????????// @description 如果一個(gè)驗(yàn)證不通過就返回
??????????if (typeof onError === 'function') {
????????????return onError.call(scope || this, _data, data);
??????????} else {
????????????return false;
??????????}
????????}
??????}
??????// @description 對獲取的數(shù)據(jù)做字段映射
??????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
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'
??????}
????};
????//如果需要緩存,可以在此設(shè)置緩存對象
????this.cacheData = null;
????this.pushValidates(function(data) {
??????return scope._baseDataValidate(data);
????});
??}
??//首輪處理返回?cái)?shù)據(jù),檢查錯(cuò)誤碼做統(tǒng)一驗(yàn)證處理
??_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
}
接下來是實(shí)際調(diào)用代碼:
let model = models.cityModel;
model.setParam({
??type: 1
});
model.execute(function(data) {
??console.log(data);
??debugger;
});
數(shù)據(jù)便請求結(jié)束了奴璃,有了這個(gè)類我們可以做非常多的工作悉默,比如:
① 前端設(shè)置統(tǒng)一的錯(cuò)誤碼處理邏輯
② 前端打點(diǎn),統(tǒng)計(jì)所有的接口響應(yīng)狀態(tài)
③ 每次請求相同參數(shù)做數(shù)據(jù)緩存
④ 這個(gè)對于錯(cuò)誤處理很關(guān)鍵溺健,一般來說前端出錯(cuò)很大可能都是后端數(shù)據(jù)接口字段有變化麦牺,而這種錯(cuò)誤是比較難尋找的钮蛛,如果我這里做一個(gè)統(tǒng)一的收口,每次數(shù)據(jù)返回記錄所有的返回字段的標(biāo)志上報(bào)呢剖膳,就以這個(gè)城市數(shù)據(jù)為例魏颓,我們可以這樣做:
class CityModel extends DemoModel {
??constructor() {
????super();
????this.url = '/city/getstartcitys';
??}
??//每次數(shù)據(jù)訪問成功,錯(cuò)誤碼為0時(shí)皆會(huì)執(zhí)行這個(gè)回調(diào)
??onDataSuccess(fdata, data) {
????super.onDataSuccess(fdata, data);
????//開始執(zhí)行自我邏輯
????let o = {
??????_indate: new Date().getTime()
????};
????for(let k in fdata) {
??????o[k] = typeof fdata[k];
????}
????//執(zhí)行數(shù)據(jù)上報(bào)邏輯
????console.log(JSON.stringify(o));
??}
}
這里就會(huì)輸出以下信息:
{"_indate":1533436847778,"cities":"object","hots":"object","total":"number","page":"string"}
如果對數(shù)據(jù)要求非常嚴(yán)苛吱晒,對某些接口做到字段層面的驗(yàn)證甸饱,那么加一個(gè)Validates驗(yàn)證即可,這樣對接口的控制會(huì)最大化仑濒,就算哪次出問題叹话,也能很好從數(shù)據(jù)分析系統(tǒng)之中可以查看到問題所在,如果我現(xiàn)在想要一個(gè)更為具體的功能呢墩瞳?我想要首次請求一個(gè)接口時(shí)便將其數(shù)據(jù)記錄下來驼壶,第二次便不再請求呢,這個(gè)時(shí)候我們之前設(shè)計(jì)的數(shù)據(jù)持久層便派上了用處:
let Store = require('./abstract-store.js');
class CityStore extends Store {
??constructor() {
????super();
????this.key = 'DEMO_CITYLIST';
????//30分鐘過期時(shí)間
????this.lifeTime = 30;
??}
}
module.exports = {
??cityStore: new CityStore
}
class CityModel extends DemoModel {
??constructor() {
????super();
????this.url = '/city/getstartcitys';
????this.cacheData = Stores.cityStore;
??}
??//每次數(shù)據(jù)訪問成功喉酌,錯(cuò)誤碼為0時(shí)皆會(huì)執(zhí)行這個(gè)回調(diào)
??onDataSuccess(fdata, data) {
????super.onDataSuccess(fdata, data);
????//開始執(zhí)行自我邏輯
????let o = {
??????_indate: new Date().getTime()
????};
????for(let k in fdata) {
??????o[k] = typeof fdata[k];
????}
????//執(zhí)行數(shù)據(jù)上報(bào)邏輯
????console.log(JSON.stringify(o));
??}
}
這個(gè)時(shí)候第二次請求時(shí)候便會(huì)直接讀取緩存了
接下來便可以回到我們的頁面渲染邏輯了热凹,這個(gè)時(shí)候就變得非常簡單了:
<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>
//用于設(shè)置城市數(shù)據(jù)
??setCityData: function(data) {
????data = data.cities;
????let citys = {}, sortCitys = [];
????let k, gname, name, i, tmp = {}, index;
????//首先處理每個(gè)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泪电,于是我們首頁的功能便完成了:
經(jīng)過一個(gè)多星期的學(xué)習(xí)般妙,我們慢慢的完成了我們的首頁,好像也就幾個(gè)元素相速,但是后面的一切卻不簡單啊碟渺,我們明天繼續(xù)完成list頁面邏輯,便開始總結(jié)小程序開發(fā)突诬。
感興趣的小伙伴苫拍,可以關(guān)注公眾號(hào)【grain先森】巷挥,回復(fù)關(guān)鍵詞 “小程序”绘迁,獲取更多資料,更多關(guān)鍵詞玩法期待你的探索~