前言

接上文:微信小程序开发05-日历组件的实现

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

这里来说一说我们的理念,我们也学习小程序开发有一周多了,从近期的使用上来说,小程序可以作为底层,但是缺少一个框架层,这个框架层需要提供:

① 组件库

② 更好的代码组织方式,也就是让我们可以做到轻松的组件化开发

我们从最开始到现在,都在沿着这个方向去分解小程序学习,其实小程序本身的东西差不多了,但是我们代码过程中有时候却越高越复杂,多了很多封装,其实这所有的复杂都是为了设置一个基本的架构,一个标准的开发模式,让后面写业务代码的同学能更高效的写代码,经过一年多的发展,事实上这种较为成熟的框架已经有了,比如我们正在使用的:

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

但是,可以看到小程序基本还是原生JS,这其实是个非常好的学习整理机会,所以我这边一步步和大家对小程序进行了拆分,期望能形成一套还能用的雏形,帮助大家理解,所以我们继续今天的学习吧,为了降低单页面难度,我们将首页进行下改造。

首页

首页做了一点改造,变成了这个样式了:

这里需要三个点击时间点,因为日历组件,我们昨天就做好了,而他这个出发日期事实上就是我们日历组件的selecedDate,处理这块逻辑:

 <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-span3">
出发日期</view>
<view class="c-span9 js-arrive search-line-txt">
{{calendarSelectedDate || '请选择出发日期'}} </view>
</view>

点击时候我们弹出我们的日历,这个时候我们日历模块释放一个事件显示日历:

PS:template不与页面级别WXML共享一个作用域,所以我暂时都采用的include引入

 <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-span3">
出发日期</view>
<view class="c-span9 js-arrive search-line-txt">
{{calendarSelectedDateStr}}</view>
</view>
 /*
事实上一个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日')
}
}

显然,这里的日历这样摆设有点丑,我们这里将其封装成一个弹出层,所以我们这里再做一个容器类组件,专门用于装载页面样式用:

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

但是这里也引起了其他问题,因为引入了shadow-dom概念,我的样式不能重用,组件内部样式与外部是不能通信的,但是这里是页面级别容器,内容的样式肯定是来源页面的,这里没什么问题,所以我们这里显示的是正确的,但是我这里想做一个出格一点的操作,我想用样式将这里日历月标题换个位置:

而日历组件和外部是不能通信的,我们这里该如何处理呢,我这里想了两个方案:

① 设置一个全局使用的组件库样式,让所有组件继承,但是不知道这里对性能是否有影响,因为这样的话体积不会太小

② 小程序设计了可以传入组件的方法,比如我们这里的日历组件我们可以这样改变其样式

 .calendar-cm-month {
position: absolute;
top:;
height: 90rpx;
line-height: 90rpx;
width: 100%;
color: #00b358;
text-align: center;
}
 Component({
2 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上查看,总而言之,我们的页面变成了这个样子了:

PS:这里发现一个不知道是不是坑点的点,我们这里属性传递的是一个date对象,但是到了组件层之间变成了对象,不知微信底层做了什么:

calendarDisplayTime: new Date()

好像变成了一个空对象,这里可能发生的情况是,经过传递的日期对象会被某种特殊处理,但是具体发生了什么事情就不知道了,这个却引起了我们不小的麻烦,这里大概去翻开了一下源码:

极有可能,小程序本身就不支持date属性的传递,我们的日历组件能跑起来的原因是什么,我这里都有点疑惑了......

而且就算以对象方式传递到组件的date类型都会变成莫名其妙的东西:

     ttt: {
key: 'date',
value: selectedDate
},

这个特性有点令人抓不住头脑了,这里根据探查,很有可能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日')
}
}

虽然看上去恶心了一点,但是总是不会出什么明显的问题,忍一忍吧......日期部分基本结束了,还有些小的限制没有做上,比如哪些时段能选,哪些不能,这块就有待各位发现吧,我们这里毕竟是学习,做细了很花功夫,我们接下来做出发目的地选择部分。

数据请求

城市列表

城市列表这里看起来需要新开一个页面,但是我这里想做在一个页面中,考虑篇幅,我们使用弹出层容器组件看并且尽量削弱一些特性,几天下来别说写的还有些累......

这个又作为首页的一个模块而存在:

 <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>
 /*
事实上一个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
}))

这里我们开始有数据请求模块了,小程序使用这个接口请求数据,这里比较尴尬的是他要设置域名白名单:

wx.request(OBJECT)

而我们使用的是测试账号没有可以设置的地方,所以我们还是去申请个小程序账号吧...配置成功,我们继续代码:

可以看到数据请求已经回来了,但是我们一般来说一个接口不止会用于一个地方,每次重新写好像有些费事,加之我这里想将重复的请求缓存起来,所以我们这里封装一套数据访问层出来

数据缓存(持久层)

之前在浏览器中,我们一般使用localstorage存储一些不太更改的数据,微信里面提供了接口处理这一切:

wx.setStorage(OBJECT)

我们这里需要对其进行简单封装,便与后面更好的使用,一般来说有缓存就一定要有过期,所以我们动态给每个缓存对象增加一个过期时间:

 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: 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;
}
}
//@override
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
 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;
});

数据便请求结束了,有了这个类我们可以做非常多的工作,比如:

① 前端设置统一的错误码处理逻辑

② 前端打点,统计所有的接口响应状态

③ 每次请求相同参数做数据缓存

④ 这个对于错误处理很关键,一般来说前端出错很大可能都是后端数据接口字段有变化,而这种错误是比较难寻找的,如果我这里做一个统一的收口,每次数据返回记录所有的返回字段的标志上报呢,就以这个城市数据为例,我们可以这样做:

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

如果对数据要求非常严苛,对某些接口做到字段层面的验证,那么加一个Validates验证即可,这样对接口的控制会最大化,就算哪次出问题,也能很好从数据分析系统之中可以查看到问题所在,如果我现在想要一个更为具体的功能呢?我想要首次请求一个接口时便将其数据记录下来,第二次便不再请求呢,这个时候我们之前设计的数据持久层便派上了用处:

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

这个时候第二次请求时候便会直接读取缓存了

接下来便可以回到我们的页面渲染逻辑了,这个时候就变得非常简单了:

 <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生成唯一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页面逻辑,便开始总结小程序开发

微信小程序开发06-一个业务页面的完成的更多相关文章

  1. 微信小程序开发--路由切换,页面重定向

    这段时间开发了一个微信小程序,虽然小程序的导航API 官方文档写得很详细,但是在具体开发过程中还是会遇到很多不明白,或者一时转不过弯的地方. 1.页面切换传参,参数读取 1.1  wx.navigat ...

  2. 微信小程序开发 [06] 一些补充的知识点

    0.写在前面的话 前几章的内容串联起来,基本上已经能写比较基础的小程序页面逻辑了,当然,wxml和wxss的我并没有写,因为前端我也并不擅长.这个章节,准备随便叨叨,然后补充一些之前没有提到的基础知识 ...

  3. 微信小程序开发——以简单易懂的浏览器页面栈理解小程序的页面路由

    前言: 对于小程序的页面路由,如果没有一定开发经验的话,理解起来还是会有些困难的.哪怕是有一定小程序开发经验的开发者,能够完全理解掌握的恐怕也不多. 这里就以另外一种方式来详细的介绍小程序的页面栈及路 ...

  4. 微信小程序开发2-第一个小程序开发准备

    1.首先在官网上注册一个账号( https://mp.weixin.qq.com/ )申请一个AppID(类似于人的身份证,小程序也需要身份证) 注册过程不多说 2.安装开发工具( https://m ...

  5. 微信小程序开发(四)页面跳转

    承接上篇博客. 通过点击按钮跳转到新的页面. 先创建新页面home: 代码如下: // home.js Page({}) // 注册页面 // home.json {} // home.wxml &l ...

  6. 微信小程序开发 如何退出当前页面

    默认是在首页 wx.navigateBack({     delta: -1 });     详情参考. https://mp.weixin.qq.com/debug/wxadoc/dev/api/u ...

  7. 微信小程序开发07-列表页面怎么做

    接上文:微信小程序开发06-一个业务页面的完成 github地址:https://github.com/yexiaochai/wxdemo 我们首页功能基本完成,我对比了下实际工作中的需求,完成度有7 ...

  8. 微信小程序开发03-这是一个组件

    编写组件 基本结构 接上文:微信小程序开发02-小程序基本介绍 我们今天先来实现这个弹出层: 之前这个组件是一个容器类组件,弹出层可设置载入的html结构,然后再设置各种事件即可,这种组件有一个特点: ...

  9. 【云开发】10分钟零基础学会做一个快递查询微信小程序,快速掌握微信小程序开发技能(轮播图、API请求)

    大家好,我叫小秃僧 这次分享的是10分钟零基础学会做一个快递查询微信小程序,快速掌握开发微信小程序技能. 这篇文章偏基础,特别适合还没有开发过微信小程序的童鞋,一些概念和逻辑我会讲细一点,尽可能用图说 ...

随机推荐

  1. HEOI2018——welcome to NOI2018

    我不得不和烈士和小丑走在同一道路上,  万人都要将火熄灭,  我一人独将此火高高举起,  我借此火得度一生的茫茫黑夜. ——海子 弹指一瞬间,翘首以盼的HEOI2018就来了. 我,一个滑稽的小丑,带 ...

  2. BZOJ_2594_[Wc2006]水管局长数据加强版_LCT

    BZOJ_2594_[Wc2006]水管局长数据加强版_LCT Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供 ...

  3. Eigen实现坐标转换

    (<视觉SLAM十四讲>第三讲习题7)设有小萝卜一号和二号在世界坐标系中.一号位姿q1 = [0.35, 0.2, 0.3, 0.1],t1=[0.3, 0.1, 0.1].二号位姿q2= ...

  4. Java开发者必备的10大学习网站,送给入门学习java的你,请收下!

    作为开发者来说,必备的除了对编码的热情还要有自己的一套技巧,另外不可缺少的就是平时学习的网站.以下本人收集的 Java 开发者必备的网站,这些网站可以提供信息.以及一些很棒的讲座 , 还能解答一般问题 ...

  5. python设计模式-观察者

    定义: 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖的对象都会得到通知并被自动更新. 观察者模式是对象的行为模式,又叫发布-订阅(pubish/subscribe)模式,模型 ...

  6. Python函数小节

    定义函数时,默认参数必须指向不变的对象 参数为可变对象时,正常调用的时候,结果没有问题,但是当使用默认参数的时候,结果就会和理想的有差距. In [78]: def add(L=[]): ...: L ...

  7. Python猫荐书系列:文也深度学习,理也深度学习

    最近出了两件大新闻,相信大家可能有所耳闻. 我来当个播报员,给大家转述一下: 1.中国队在第 11 界罗马尼亚数学大师赛(RMM)中无缘金牌.该项赛事是三大国际赛事之一,被誉为中学奥数的最高难度.其中 ...

  8. 【Java】几道常见的秋招面试题

    前言 只有光头才能变强 Redis目前还在看,今天来分享一下我在秋招看过(遇到)的一些面试题(相对比较常见的) 0.final关键字 简要说一下final关键字,final可以用来修饰什么? 这题我是 ...

  9. MaxCompute 2.0复杂数据类型之array

    1. 含义 类似于Java中的array.有序.可重复. 2. 场景 什么样的数据,适合使用array类型来存储呢?这里列举了几个我在开发中实际用到的场景. 2.1 标签类的数据 为什么说标签类数据适 ...

  10. 第6章 令牌撤销端点(Token Revocation Endpoint) - IdentityModel 中文文档(v1.0.0)

    OAuth 2.0令牌撤销的客户端库是作为扩展方法提供的HttpClient. 以下代码撤消撤销端点处的访问令牌令牌: var client = new HttpClient(); var resul ...