菜单

微信小程序支付之页面注册

2019年5月2日 - Json

微信小程序开垦06-1个业务页面包车型地铁落成

2018/08/07 · 基础才具 ·
小程序

初稿出处:
叶小钗   

页面Page是object

前言

接上文:微信小程序支付0伍-日历组件的得以达成

github地址:https://github.com/yexiaochai/wxdemo

这里来讲1说咱俩的眼光,大家也学习小程序支付有7日多了,从眼下的应用上的话,小程序能够作为底层,可是缺点和失误一个框架层,那些框架层需求提供:

① 组件库

二 更加好的代码组织方式,也正是让大家能够达成轻巧的组件化开拓

小编们从最开首到目前,都在沿着那几个方向去解释小程序学习,其实小程序本人的事物大概了,不过大家代码进度中偶尔却越高越复杂,多了大多封装,其实那全部的盘根错节都感到了设置二个着力的架构,三个职业的费用形式,让前面写作业代码的同室能更加高效的写代码,经过一年多的提高,事实上那种较为成熟的框架已经有了,比方大家正在使用的:

https://tencent.github.io/wepy/

只是,能够见到小程序基本还是原生JS,那实在是个要命好的就学整理机会,所以作者那边一步步和咱们对小程序举办了拆分,期望能形成一套还是能用的雏形,帮衬我们领略,所以大家继续今日的上学呢,为了下跌单页面难度,大家将首页举办下改变。

Page({
  data:{
    String1
  },
  onLoad:function(options){
    // 生命周期函数–监听页面加载

首页

首页做了好几更换,造成了这么些样式了:

图片 1

此间要求多少个点击时间点,因为日历组件,大家后日就办好了,而她那个出发日期事实上就是我们日历组件的selecedDate,管理那块逻辑:

<template name=”searchbox”> <view class=”c-row search-line”
data-flag=”start”> <view class=”c-span三”> 出发</view>
<view class=”c-span九 js-start search-line-txt”>
请接纳出发地</view> </view> <view class=”c-row
search-line” data-flag=”arrive”> <view class=”c-span三”>
达到</view> <view class=”c-span玖 js-arrive search-line-txt”>
请选取达到地</view> </view> <view class=”c-row
search-line” data-flag=”arrive”> <view class=”c-span三”>
出发日期</view> <view class=”c-span九 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
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>

<view class=”c-row search-line” data-flag=”arrive”> <view
class=”c-span三”> 出发日期</view> <view class=”c-span玖js-arrive search-line-txt”> {{calendarSelectedDate ||
‘请采抽取发日期’}} </view> </view>

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引进

图片 2

<view class=”c-row search-line” data-flag=”start”> <view
class=”c-span三”> 出发</view> <view class=”c-span玖 js-start
search-line-txt”> 请选用出发地</view> </view> <view
class=”c-row search-line” data-flag=”arrive”> <view
class=”c-span3″> 到达</view> <view class=”c-span玖 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-span玖 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
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" />

<view class=”c-row search-line” data-flag=”arrive”
ontap=”showCalendar”> <view class=”c-span三”>
出发日期</view> <view class=”c-span玖 js-arrive
search-line-txt”> {{calendarSelectedDateStr}}</view>
</view>

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>

/*
事实上一个mod就只是2个目的,只但是为了便利拆分,将对象分拆成三个个的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
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个器皿类组件,专门用来装载页面样式用:

图片 3

图片 4

<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
<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>

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概念,我的体裁不能够重用,组件内部样式与外表是无法通讯的,可是此地是页面等级容器,内容的体制肯定是来自页面包车型地铁,这里没什么难点,所以大家这里显得的是不错的,不过本人那边想做2个特殊一点的操作,小编想用样式将这里日历月标题换个岗位:

图片 5

而日历组件和外部是不可能通讯的,大家这里该怎么管理呢,小编那边想了七个方案:

一设置二个大局使用的组件库样式,让抱有组件承继,不过不明白这里对质量是不是有震慑,因为这么的话体量不会太小

二小程序设计了足以流传组件的章程,比如大家这里的日历组件大家可以那样改动其样式

.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
.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) } } })

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)
    }
  }
})

<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>

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上查看,简单来讲,大家的页面形成了那几个样子了:

图片 6

PS:这里发掘叁个不知道是或不是坑点的点,我们那边属性传递的是1个date对象,可是到了组件层之间变为了目的,不知微信底层做了怎么:

JavaScript

calendarDisplayTime: new Date()

1
calendarDisplayTime: new Date()

图片 7

好像形成了3个空对象,这里只怕发生的情况是,经过传递的日期对象会被某种特殊管理,不过现实发生了何等业务就不领悟了,这么些却引起了作者们比一点都不小的辛勤,这里大概去查看了弹指间源码:

图片 8

极有一点都不小可能率,小程序本人就不协理date属性的传递,大家的日历组件能跑起来的原故是何许,小编这里都有点狐疑了……

还要不怕以目的格局传递到零部件的date类型都会化为无缘无故的东西:

ttt: { key: ‘date’, value: selectedDate },

1
2
3
4
ttt: {
   key: ‘date’,
   value: selectedDate
},

图片 9

那天性情有点令人抓不住头脑了,这里根据考查,很有异常的大希望Component将date对象传入WXML解释时候,自动转为了日期字符串了,所以大家这里看上去是目的的事物其实是字符串,这里的提出是:跟组件的date传递,暂且全体选拔字符串替代,以防自个小儿麻痹症烦,然后大家先将事先的日历操作全体成为字符串,再为大家的内外开关加上事件:

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
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忍吧……日期部分基本告竣了,还某些小的范围未有做上,比方如什么日期段能选,哪些不能够,那块就有待各位开掘呢,大家这里终归是学习,做细了很花武术,我们接下去做出发目标地选取一些。

数量请求

    String2
  },
  onReady:function(){
    // 生命周期函数–监听页面初次渲染落成

城市列表

都会列表这里看起来须求新开三个页面,不过笔者这边想做在贰个页面中,思量篇幅,大家使用弹出层容器组件看还要尽量减弱一些特点,几天下来别说写的还有个别累……

以此又作为首页的一个模块而留存:

图片 10

<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
<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>

/*
事实上2个mod就只是2个目的,只可是为了有利于拆分,将对象分拆成一个个的mod
1个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
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: ”
  }
}

首页调用代码:

//获取公共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
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
}))

图片 11

那边我们开始有数据请求模块了,小程序选取这一个接口请求数据,这里相比较难堪的是她要设置域名白名单:

wx.request(OBJECT)

1
wx.request(OBJECT)

而小编辈应用的是测试账号未有可以安装的地方,所以我们还是去报名个小程序账号吧…配置成功,大家继续代码:

图片 12

能够见见数据请求已经再次来到了,可是我们一般的话3个接口不止会用于叁个地点,每一回重复写好像有个别麻烦,加之自身这里想将再也的呼吁缓存起来,所以我们那边封装一套数据访问层出来

三个页面只会调用贰遍,代表页面已经计划妥帖,可以和视图层进行交互。

数码缓存(持久层)

前边在浏览器中,大家一般选择localstorage存款和储蓄一些不太改换的数码,微信里面提供了接口管理那全数:

wx.setStorage(OBJECT)

1
wx.setStorage(OBJECT)

大家那边要求对其进展简易包装,便与后边越来越好的行使,一般的话有缓存就一定要有逾期,所以大家动态给种种缓存对象扩大3个过期光阴:

class Store { constructor(opts) { if(typeof opts === ‘string’) this.key
= opts; else Object.assign(this, opts);
//假如未有传过期时间,则暗中同意2玖分钟 if(!this.lifeTime) this.lifeTime = 一;
//当地缓存用以存放全部localstorage键值与过期日期的照射 this._keyCache =
‘SYSTEM_KEY_TIMEOUT_MAP’; } //获取过期时间,单位为阿秒 _getDeadline()
{ return this.lifeTime * 60 * 一千; }
//获取一个数目缓存对象,存能够异步,获取自笔者一块儿就能够 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
为格式化后的央求参数,用于同壹请求例外参数时候回来新数据,举例列表为Hong Kong市的城市,后切换为香港,会咬定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
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

以此类的利用也格外轻易,这里举个例证:

sss = new global.Store({key: ‘qqq’, lifeTime: 壹}) sss.set({a: 一}, 二)
sss.get()//因为未有秘钥会是null sss.get(2)//sss.get(2)

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)

以此时候我们开头写咱俩多少请求的类:

第三依然促成了三个抽象类和三个作业基类,然后发轫在业务层请求数据:

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'&gt;@override&lt;/a&gt;
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 开拓者能够流传1组求证措施实行表达 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
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

图片 13图片 14

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
德姆oModel { constructor() { super(); this.url = ‘/city/getstartcitys’; }
} module.exports = { cityModel: new CityModel } 业务基类

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
 
}
 
业务基类

接下去是实际上调用代码:

let model = models.cityModel; model.setParam({ type: 1 });
model.execute(function(data) { console.log(data); debugger; });

1
2
3
4
5
6
7
8
let model = models.cityModel;
model.setParam({
  type: 1
});
model.execute(function(data) {
  console.log(data);
  debugger;
});

数量便伸手甘休了,有了这些类大家得以做尤其多的专业,比方:

壹 前端安装统一的错误码管理逻辑

贰 前端照望,计算全体的接口响应状态

3 每便请求同样参数做多少缓存

④这么些对于错误管理很爱护,一般的话前端出错十分的大或然皆现在端数据接口字段有变动,而那种指鹿为马是比较难寻觅的,若是自个儿那边做一个统1的愈合,每便数据重临记录全体的回到字段的表明上报呢,就以那些城市数量为例,大家得以这么做:

class CityModel extends 德姆oModel { 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
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));
  }
}

此间就能够输出以下新闻:

{“_indate”:1533436847778,”cities”:”object”,”hots”:”object”,”total”:”number”,”page”:”string”}

1
{"_indate":1533436847778,"cities":"object","hots":"object","total":"number","page":"string"}

若是对数据供给特别严苛,对一些接口做到字段层面包车型大巴求证,那么加贰个Validates验证就可以,那样对接口的调控会最大化,尽管哪次出标题,也能很好从数据分析系统之中能够查看到难题所在,假如本人昨天想要三个尤其具体的功效吗?小编想要首次呼吁三个接口时便将其数量记录下来,第三回便不再请求呢,这一年大家以前设计的数码持久层便派上了用处:

let Store = require(‘./abstract-store.js’); class CityStore extends
Store { constructor() { super(); this.key = ‘DEMO_CITYLIST’;
//三十多分钟过期时间 this.lifeTime = 30; } } module.exports = { cityStore:
new CityStore }

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
}

class CityModel extends 德姆oModel { 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
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));
  }
}

其暂且候第3回呼吁时候便会直接读取缓存了

图片 15

接下去便足以回来大家的页面渲染逻辑了,今年就变得十分简单了:

<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
<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>

//用于安装城市数量 setCityData: function(data) { data = data.cities; let
citys = {}, sortCitys = []; let k, gname, name, i, tmp = {}, index;
//首先管理每一种name生成唯1K 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()

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: ”
    });
  },

图片 16

然后大家这里为组件绑定事件等就相比简单了,我们能够自个儿看github,于是大家首页的效益便落成了:

图片 17

通过1个多星期的学习,我们慢慢的完成了大家的首页,好像也就多少个成分,可是后边的一切却不轻易啊,大家今天卫冕产生list页面逻辑,便伊始总括小程序支付

1 赞 收藏
评论

图片 18

对分界面包车型大巴装置如wx.setNavigationBarTitle请在onReady随后设置
    String3
  },
  onShow:function(){
    // 生命周期函数–监听页面展现

    每一趟张开页面都会调用一回。
    String4
  },
  onHide:function(){
    // 生命周期函数–监听页面隐藏

navigateTo或底部tab切换时调用。
    String5
  },
  onUnload:function(){
    // 生命周期函数–监听页面卸载

redirectTonavigateBack的时候调用。
    String6
  },
  onPullDownRefresh: function() {
    // 页面相关事件管理函数–监听用户下带动作

    String7
  },
  onReachBottom: function() {
    // 页面上拉触底事件的管理函数
    String8
  },
  onShareAppMessage: function() {
    // 用户点击右上角分享

    return {
      title: ‘title’, // 分享标题
      desc: ‘desc’, // 分享描述
      path: ‘path’ // 分享路径
    }
  }
})

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图