微信小程序開發(fā)(6):一個(gè)業(yè)務(wù)頁面的完成

作者:葉小釵?

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)鍵詞玩法期待你的探索~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末近范,一起剝皮案震驚了整個(gè)濱河市催束,隨后出現(xiàn)的幾起案子集峦,更是在濱河造成了極大的恐慌,老刑警劉巖抠刺,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件塔淤,死亡現(xiàn)場離奇詭異,居然都是意外死亡速妖,警方通過查閱死者的電腦和手機(jī)高蜂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來罕容,“玉大人备恤,你說我怎么就攤上這事稿饰。” “怎么了露泊?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵喉镰,是天一觀的道長。 經(jīng)常有香客問我惭笑,道長侣姆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任沉噩,我火速辦了婚禮捺宗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘川蒙。我一直安慰自己蚜厉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布畜眨。 她就那樣靜靜地躺著弯囊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪胶果。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天斤斧,我揣著相機(jī)與錄音早抠,去河邊找鬼。 笑死撬讽,一個(gè)胖子當(dāng)著我的面吹牛蕊连,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播游昼,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼甘苍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了烘豌?” 一聲冷哼從身側(cè)響起载庭,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎廊佩,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體标锄,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡顽铸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年料皇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娜膘。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡劲绪,死狀恐怖贾富,靈堂內(nèi)的尸體忽然破棺而出颤枪,到底是詐尸還是另有隱情,我是刑警寧澤淑际,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布畏纲,位于F島的核電站,受9級(jí)特大地震影響春缕,放射性物質(zhì)發(fā)生泄漏盗胀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一锄贼、第九天 我趴在偏房一處隱蔽的房頂上張望票灰。 院中可真熱鬧,春花似錦宅荤、人聲如沸屑迂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惹盼。三九已至,卻和暖如春惫确,著一層夾襖步出監(jiān)牢的瞬間手报,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工改化, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留昧诱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓所袁,卻偏偏與公主長得像盏档,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子燥爷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • pyspark.sql模塊 模塊上下文 Spark SQL和DataFrames的重要類: pyspark.sql...
    mpro閱讀 9,451評(píng)論 0 13
  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些閱讀 2,030評(píng)論 0 2
  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi閱讀 7,325評(píng)論 0 10
  • 或許真的是祖先庇佑,在太爺年過半百之時(shí)稚配,爺爺?shù)牡絹碜屗老踩艨瘛?還是一個(gè)大旱天畅涂,幾個(gè)村民去老廟剛求雨回來。眼瞅著...
    南炎青玄閱讀 1,245評(píng)論 0 1
  • 問卷星(有企業(yè),非免費(fèi)系統(tǒng)冒萄。免費(fèi)功能有限制)https://www.wjx.cn/ 優(yōu)秀的出題系統(tǒng)https://...
    AISpider閱讀 511評(píng)論 0 0