一、场景需求
1.统计某个控制器UIViewController家长次数;
2.统计某个UIButton点击次数;
3.统计某个方法执行次数;
4.统计UITableView的Cell点击次数;
二、技术选型对比
1.手动复制统计代码逻辑粘贴到对应的类、方法中
工作量大,可维护性差,仅适用于统计埋点较少的情形;
2.通过继承和重写系统方法
利用写好的统计的一个基类,让需要统计的类继承自该基类,或者调用重写过统计逻辑的按钮基类等;
3.分类:添加类方法或者示例方法
将统计逻辑封装在分类方法里面,在需要统计的地方导入并调用分类方法;
4.替换系统方法分类:通过runtime的方法
利用Method Swizzling机制进行方法替换:替换 系统方法(原来的需要在里面统计却不含统计逻辑的方法) 为 新方法(新的包含了统计逻辑的方法)
5.AOP的方法
利用Aspect框架对需要进行统计的方法进行挂钩(hook),并注入包含了统计逻辑的代码块(block)
三、技术实现
需求1:监听全局的某一类的统一方法
1.Runtime Method Swizzling方案
方案特点:被监听的方法单一,但会影响全局的所有的类的该方法
1 | UIViewController+Trace |
2.AOP编程方案 - 为VC设计的分类
方案特点:被监听的方法单一,但会影响全局的所有的类的该方法
Aspects 是iOS平台一个轻量级的面向切面编程(AOP)框架,只包括两个方法:一个类方法,一个实例方法;
1 | + (id)aspect_hookSelector:(SEL)selector withOptions:(AspectOptions)options usingBlock:(id)block error:(NSError **)error; |
1 |
|
3.AOP编程方案 - 为全局AppDelegate设计的分类
方案特点:
需要监听不同类,不同按钮,系统方法,及表单元点击事件;
是可代码配置需要监听的清单字典,并且需要注入的统计代码块block也可以写在这个清单里面;
1 | AppDelegate+Trace.m |
4.在AppDelegate的类方法中根据Plist监听清单进行HOOK
方案特点
需要监听不同类,不同按钮,系统方法,及表单元点击事件;
是可代码配置需要监听的清单Plist,但是不能将需要注入的统计代码块block写在这个清单Plist里面;
EventList.plist
AspectMananer.m
#pragma mark --- 监控button的点击事件
+ (void)trackBttonEvent{
__weak typeof(self) ws = self;
//设置事件统计
//放到异步线程去执行
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//读取配置文件,获取需要统计的事件列表
NSString *path = [[NSBundle mainBundle] pathForResource:@"EventList" ofType:@"plist"];
NSDictionary *eventStatisticsDict = [[NSDictionary alloc] initWithContentsOfFile:path];
for (NSString *classNameString in eventStatisticsDict.allKeys) {
//使用运行时创建类对象
const char * className = [classNameString UTF8String];
//从一个字串返回一个类
Class newClass = objc_getClass(className);
NSArray *pageEventList = [eventStatisticsDict objectForKey:classNameString];
for (NSDictionary *eventDict in pageEventList) {
//事件方法名称
NSString *eventMethodName = eventDict[@"MethodName"];
SEL seletor = NSSelectorFromString(eventMethodName);
NSString *eventId = eventDict[@"EventId"];
[ws trackEventWithClass:newClass selector:seletor eventID:eventId];
[ws trackTableViewEventWithClass:newClass selector:seletor eventID:eventId];
[ws trackParameterEventWithClass:newClass selector:seletor eventID:eventId];
}
}
});
}
#pragma mark -- 1.监控button和tap点击事件(不带参数)
+ (void)trackEventWithClass:(Class)klass selector:(SEL)selector eventID:(NSString*)eventID{
[klass aspect_hookSelector:selector withOptions:AspectPositionAfter usingBlock:^(id
aspectInfo) {
NSString *className = NSStringFromClass([aspectInfo.instance class]);
NSLog(@"className--->%@",className);
NSLog(@"event----->%@",eventID);
if ([eventID isEqualToString:@"xxx"]) {//
[EJServiceUserInfo isLogin]?[MobClick event:eventID]:[MobClick event:@"???"];
}else{//
[MobClick event:eventID];
}
} error:NULL];
}
#pragma mark -- 2.监控button和tap点击事件(带参数)
+ (void)trackParameterEventWithClass:(Class)klass selector:(SEL)selector eventID:(NSString*)eventID{
[klass aspect_hookSelector:selector withOptions:AspectPositionAfter usingBlock:^(id
aspectInfo,UIButton *button) {
NSLog(@"button---->%@",button);
NSString *className = NSStringFromClass([aspectInfo.instance class]);
NSLog(@"className--->%@",className);
NSLog(@"event----->%@",eventID);
} error:NULL];
}
#pragma mark -- 3.监控tableView的点击事件
+ (void)trackTableViewEventWithClass:(Class)klass selector:(SEL)selector eventID:(NSString*)eventID{
[klass aspect_hookSelector:selector withOptions:AspectPositionAfter usingBlock:^(id
aspectInfo,NSSet *touches, UIEvent *event) {
NSString *className = NSStringFromClass([aspectInfo.instance class]);
NSLog(@"className--->%@",className);
NSLog(@"event----->%@",eventID);
NSLog(@"section---->%@",[event valueForKeyPath:@"section"]);
NSLog(@"row---->%@",[event valueForKeyPath:@"row"]);
NSInteger section = [[event valueForKeyPath:@"section"]integerValue];
NSInteger row = [[event valueForKeyPath:@"row"]integerValue];
//统计事件
if (section == 0 && row == 1) {//
[MobClick event:eventID];
}
} error:NULL];
}
Appdelegate.m调用
[AspectMananer trackBttonEvent];
参考资料:
1.iOS数据埋点统计方案
2.iOS数据埋点
一、Map组件
1.属性
属性名 | 类型 | 默认值 | 描述 |
---|---|---|---|
longitude | Number | 地图组件的经纬度必填, 如果不填经纬度则默认值是北京的经纬度 | 中心经度 |
latitude | Number | 地图组件的经纬度必填, 如果不填经纬度则默认值是北京的经纬度 | 中心纬度 |
scale | Number | 16 | 缩放级别 取值范围5 - 18 |
markers | Array | 标记点 | |
covers | Array | 即将移除,使用markers | |
polyline | Array | 路线 | |
circles | Array | 圆 | |
controls | Array | 控件 | |
include-points | Array | 缩放视野以包含所有给定的坐标点 | |
show-location | Boolean | 显示带有方向的当前定位点 | |
bindmarkertap | EventHandle | 点击标记点时触发 | |
bindcallouttap | EventHandle | 点击标记对应的气泡时触发 | |
bindcontroltap | EventHandle | 点击控件时触发 | |
bindregionchange | EventHandle | 视野发生变化时触发 | |
bindtap | EventHandle | 点击地图时触发 | |
bindupdated | EventHandle | 在地图渲染更新完成时触发 |
2.makers 标记点用于在地图上显示标记的位置
属性 | 类型 | 必填 | 描述 | 备注 |
---|---|---|---|---|
id | Number | 否 | 标记点id | marker点击事件回调会返回此id,建议为每个marker设置上Number类型id,保证更新marker时有更好的性能 |
latitude | Number | 是 | 纬度 | 浮点数 范围-90 ~ 90 |
longitude | Number | 是 | 经度 | 浮点数 范围-180 ~ 180 |
title | String | 否 | 标注点名 | |
iconPath | String | 是 | 显示的图标 | 项目目录下的图片路径,支持相对路径写法,以’/‘开头则表示小程序根目录,也支持临时路径 |
rotate | Number | 否 | 旋转角度 | 顺时针旋转的角度 范围 0~360 默认0 |
alpha | Number | 否 | 标注透明度 | 默认1,无透明,范围0~1 |
width | Number | 否 | 标注图标宽度 | 默认为图片实际宽度 |
height | Number | 否 | 标注图标高度 | 默认为图片实际高度 |
callout | object | 否 | 自定义标记点上方的气泡窗口 | 可识别换行符 |
label | object | 否 | 为标记点旁边增加标签 | 可识别换行符 |
anchor | object | 否 | 经纬度在标注图标的锚点,默认在底边中点 | {x, y},x表示横向(0-1),y表示竖向(0-1)。{x: .5, y: 1} 表示底边中点 |
3.makers 上的气泡 callout
属性 | 类型 | 默认值 | 描述 |
---|---|---|---|
content | String | 文本 | |
color | String | 文本颜色 | |
fontSize | Number | 文字大小 | |
borderRadius | NUmber | callout边框圆角 | |
bgColor | String | 背景颜色 | |
padding | Number | 文本边缘留白 | |
display | String | ‘BYCLICK’:点击显示; ‘ALWAYS’:常显 | |
textAlign | String | 文本对齐方式。有效值: left, right, center |
4.makers 上气泡 label
属性名 | 类型 | 默认值 | 描述 |
---|---|---|---|
content | String | 文本 | |
color | String | 文本颜色 | |
fontSize | Number | 文字大小 | |
x | Number | label的坐标,原点是marker对应的经纬度 | |
y | Number | label的坐标,原点是marker对应的经纬度 | |
borderWidth | Number | 边框宽度 | |
borderColor | String | 边框颜色 | |
borderRadius | NUmber | 边框圆角 | |
bgColor | String | 背景颜色 | |
padding | Number | 文本边缘留白 | |
textAlign | String | 文本对齐方式。有效值: left, right, center |
5.polyline 指定一系列坐标系(从数组的第一项连线到最后一项)
属性 | 类型 | 必填 | 描述 | 备注 |
---|---|---|---|---|
points | Array | 是 | 经纬度数组 | [{latitude: 0, longitude: 0}] |
color | String | 否 | 线的颜色 | 8位十六进制表示,后两位表示alpha值,如:#000000AA |
width | Number | 否 | 线的宽度 | |
dottedLine | Boolean | 否 | 是否虚线 | 默认false |
arrowLine | Boolean | 否 | 带箭头的线 | 默认false,开发者工具暂不支持该属性 |
arrowIconPath | String | 否 | 更换箭头图标 | 在arrowLine为true时生效 |
borderColor | String | 否 | 更换箭头图标 | |
borderWidth | Number | 否 | 线的厚度 |
6.circles 在地铁上画圆
属性 | 类型 | 必填 | 描述 | 备注 |
---|---|---|---|---|
latitude | Number | 是 | 维度 | 浮点数,范围 -90 ~ 90 |
longitude | Number | 是 | 经度 | 浮点数,范围 -180 ~ 180 |
color | String | 否 | 描边的颜色 | 8位十六进制表示,后两位表示alpha值,如:#000000AA |
fillColor | String | 否 | 填充颜色 | 8位十六进制表示,后两位表示alpha值,如:#000000AA |
radius | Number | 是 | 半径 | |
strokeWidth | Number | 否 | 描边的宽度 |
7.controls 在地图上显示控件,控件不随着地图移动
属性 | 类型 | 必填 | 描述 | 备注 |
---|---|---|---|---|
id | Number | 否 | 控件id | 在控件点击事件回调会返回此id |
position | Object | 是 | 控件在地图的位置 | 控件相对地图位置 |
iconPath | String | 是 | 显示的图标 | 项目目录下的图片路径,支持相对路径写法,以’/‘开头则表示相对小程序根目录;也支持临时路径 |
clickable | Boolean | 否 | 是否可点击 | 默认不可点击 |
8.position
属性 | 类型 | 必填 | 描述 | 备注 |
---|---|---|---|---|
left | Number | 否 | 距离地图的左边界距离 | 默认0 |
top | Number | 否 | 距离地图的上边界距离 | 默认0 |
width | Number | 否 | 控件宽度 | 默认为图片宽度 |
height | Number | 否 | 控件高度 | 默认为图片高度 |
9.tips
map 组件是由客户端创建的原生组件,它的层级是最高的,不能通过 z-index 控制层级;
请勿在 scroll-view、swiper、picker-view、movable-view 中使用 map 组件;
css 动画对 map 组件无效;
map 组件使用的经纬度是火星坐标系,调用 wx.getLocation 接口需要指定 type 为 gcj02;
地图组件的经纬度必填, 如果不填经纬度则默认值是北京的经纬度;
10.eg
wxml
<view class='map'>
<map id='map' scale='16'
longitude='{{longitude}}'
latitude='{{latitude}}'
controls='{{controls}}'
markers='{{markers}}'
polyline='{{polyline}}'
style='width: 100%; height: 100%'
bindcontroltap='bindcontroltap'
bindtap='bindtap'
bindupdated='bindupdated'
bindmarkertap='bindmarkertap'
show-location='true'
bindcallouttap='bindcallouttap'
bindregionchange='bindregionchange'>
</map>
</view>
js
bindregionchange: function(){
console.log('视野发生变化时触发...')
},
bindcallouttap: function(){
console.log('点击标记点对应的气泡时触发...')
},
bindtap: function(){
console.log('点击地图时触发...')
},
bindupdated: function(){
console.log('在地图渲染更新完成时触发...')
},
bindcontroltap: function(){
console.log('点击控件时触发...')
},
bindmarkertap: function(){
console.log('点击标记点时触发...')
},
二、位置API
1.获取位置
wx.getLocation(object) - 获取当前的地理位置、速度
当用户离开小程序后,此接口无法调用;当用户点击“显示在聊天顶部”时,此接口可继续调用;
参数说明
参数 | 类型 | 必填 | 描述 |
---|---|---|---|
object参数 | |||
type | String | 否 | 默认为 wgs84 返回 gps 坐标,gcj02 返回可用于wx.openLocation的坐标 |
altitude | Boolean | 否 | 传入 true 会返回高度信息,由于获取高度需要较高精确度,会减慢接口返回速度 |
success | Function | 是 | 调用成功的回调函数 |
fail | Function | 否 | 调用失败的回调函数 |
complete | Function | 否 | 调用结束的回调函数(调用成功、失败都会执行) |
success返回参数 | |||
latitude | 纬度,浮点数,范围为-90~90,负数表示南纬 | ||
longitude | 经度,浮点数,范围为-180~180,负数表示西经 | ||
speed | 速度,浮点数,单位m/s | ||
accuracy | 位置的精确度 | ||
altitude | 高度,单位 m | ||
verticalAccuracy | 垂直精度,单位 m(Android 无法获取,返回 0) | ||
horizontalAccuracy | 垂直精度,单位 m(Android 无法获取,返回 0) |
wx.chooseLocation(object) - 打开地图选择位置
参数说明:
参数 | 类型 | 必填 | 描述 |
---|---|---|---|
object参数 | |||
success | Function | 是 | 调用成功的回调函数 |
fail | Function | 否 | 调用失败的回调函数 |
complete | Function | 否 | 调用结束的回调函数(调用成功、失败都会执行) |
success返回参数 | |||
latitude | 纬度,浮点数,范围为-90~90,负数表示南纬 | ||
longitude | 经度,浮点数,范围为-180~180,负数表示西经 | ||
name | 位置名 | ||
address | 详细地址 |
eg:
wx.getLocation({
type: 'wgs84',
success: function(res) {
var latitude = res.latitude
var longitude = res.longitude
var speed = res.speed
var accuracy = res.accuracy
}
})
2.查看位置
wx.openLocation(object) - 使用微信内置地图查看位置
参数说明
参数 | 类型 | 必填 | 描述 |
---|---|---|---|
scale | INT | 否 | 缩放比例,范围5~18,默认为18 |
latitude | Float | 是 | 纬度,浮点数,范围为-90~90,负数表示南纬 |
longitude | Float | 是 | 经度,浮点数,范围为-180~180,负数表示西经 |
name | String | 否 | 位置名 |
address | String | 否 | 详细地址 |
success | Function | 是 | 调用成功的回调函数 |
fail | Function | 否 | 调用失败的回调函数 |
complete | Function | 否 | 调用结束的回调函数(调用成功、失败都会执行) |
eg:
wx.getLocation({
type: 'gcj02', //返回可以用于wx.openLocation的经纬度
success: function(res) {
var latitude = res.latitude
var longitude = res.longitude
wx.openLocation({
latitude: latitude,
longitude: longitude,
scale: 28
})
}
})
3.组图组件控制
wx.createMapContext(mapId,this)
创建并返回 map 上下文 mapContext 对象;
在自定义组件下,第二个参数传入组件实例this,以操作组件内 <map/> 组件;
mapContext对象方法列表:
getCenterLocation object 获取当前地图中心的经纬度,返回的是gcj02坐标系可用于wx.openLocation;
moveToLocation 无参数 将地图中心移动到当前定位点,需要配合map组件的show-location使用
translateMarker object 平移marker,带动画
includePoints object 缩放视野展示所有经纬度
getRegion object 获取当前地图的视野范围
getScale object 获取当前地图的缩放级别
eg:
<!-- map.wxml -->
<map id="myMap" show-location />
<button type="primary" bindtap="getCenterLocation">获取位置</button>
<button type="primary" bindtap="moveToLocation">移动位置</button>
<button type="primary" bindtap="translateMarker">移动标注</button>
<button type="primary" bindtap="includePoints">缩放视野展示所有经纬度</button>
// map.js
Page({
onReady: function (e) {
// 使用 wx.createMapContext 获取 map 上下文
this.mapCtx = wx.createMapContext('myMap')
},
getCenterLocation: function () {
this.mapCtx.getCenterLocation({
success: function(res){
console.log(res.longitude)
console.log(res.latitude)
}
})
},
moveToLocation: function () {
this.mapCtx.moveToLocation()
},
translateMarker: function() {
this.mapCtx.translateMarker({
markerId: 0,
autoRotate: true,
duration: 1000,
destination: {
latitude:23.10229,
longitude:113.3345211,
},
animationEnd() {
console.log('animation end')
}
})
},
includePoints: function() {
this.mapCtx.includePoints({
padding: [10],
points: [{
latitude:23.10229,
longitude:113.3345211,
}, {
latitude:23.00229,
longitude:113.3345211,
}]
})
}
})
4.注意
iOS 6.3.30 type 参数不生效,只会返回 wgs84 类型的坐标信息;
一、apple协议更新问题 - 官方解答
关于您需要在开发者帐号上添加电话号码,以进行开发者帐号的更新与维护。如果您无法顺利的在电脑上添加电话号码,请您试着以您的 iOS 装置登入按照以下流程加入电话号码:
二、关于apple问题解答路径
1.apple开发者中心
2.联系我们
3.针对具体问题,选择解答方式(apple拨打给你 + 邮件)
参考资料:
1.2018苹果开发者账户忘记密保问题,导致协议无法更新解决方法
2.开发者账号忘记密保问题答案怎么办
三、HTTPS证书过期
当客户端配置的HTTPS证书过期时,AFNetWorking请求会出现code=-999,canceled 的情况,仅需要更新HTTPS证书就好。
生产客户端HTTPS证书方法:
在浏览器打开网址,如:https://developers.weixin.qq.com/miniprogram/dev/component/
点击🔒的图标,会显示弹框,显示证书,将需要的子证书拖拽到桌面上即可;
一、网络API简介
1.服务器域名配置
每个微信小程序需要事先设置一个通讯域名,小程序可以跟指定的域名进行网络通信;
包括:
普通HTTP请求(request)
上传文件(uploadFile)
下载文件(downloadFile)
WebSocket(connectSocket)
2.配置流程
配置路径:小程序后台-->设置-->开发设置-->服务器域名;
注意事项:
域名只支持https(request、uploadFile、downloadFile)和wss(connectSocket)协议;
域名不能使用IP地址和localhost,且不能带端口号;
域名必须经过ICP备案;
api.weixin.qq.com不能被配置为服务器域名,相关API也不能在小程序内调用;
开发者应将appsecret保存到后台服务器中m通过服务器使用appsecret获取accesstoken,并调用相关API;
每个接口,分别可以配置最多20个域名;
3.HTTPS证书
小程序必须使用HTTPS请求,小程序内会对服务器域名使用的HTTPS证书进行校验,失败则请求不能成功发起;
为了保证小程序兼容性,建议开发者以最高标准进行证书配置,并使用相关工具检查现有证书是否符合要求;
证书要求:
HTTPS证书必须有效;
证书必须被系统信任;
部署SSL证书的网站域名必须与证书颁发的域名一致;
证书必须在有效期内;
iOS不支持自签名证书;
iOS下证书必须满足ATS-apple transport security 的要求;
TLS必须支持1.2及以上版本;
部分CA可能不被操作系统信任;
4.跳过域名校验
微信开发工具中,可以临时开启: 开发环境不校验请求域名、TLS版本及HTTPS证书 选项,跳过服务器域名校验;
服务器域名配置成功后,建议关闭此选项,在各平台下测试,确认域名配置正确;
如果手机上出现 “打开调试模式可以发出请求,关闭调试模式无法发出请求” 的现象,请确认是否跳过了域名校验,并确认服务器域名和证书配置是否正确
5.关于请求
默认超时时间和最大超时时间 60s;
reuqest、uploadFile、downloadFile 的最大并发限制10个;
网络请求的referer header 不可设置;
固定格式:https://servicewechat.com/{appid}/{version}/page-frame.html
{appid} 为小程序的 appid,
{version} 为小程序的版本号,
版本号为 0 表示为开发版、体验版以及审核版本,
版本号为 devtools 表示为开发者工具,其余为正式版本。
小程序进入后台运行后(非置顶聊天),如果 5s 内网络请求没有结束,会回调错误信息 fail interrupted;在回到前台之前,网络请求接口调用都会无法调用
6.关于服务器返回
返回值编码
建议服务器返回值使用 UTF-8 编码。对于非 UTF-8 编码,小程序会尝试进行转换,但是会有转换失败的可能;
小程序会自动对 BOM 头进行过滤;
回调
只要成功接收到服务器返回,无论statusCode是多少,都会进入success回调;
二、发起请求
1.wx.request 发起网络请求
2.参数说明
参数名 | 类型 | 必填 | 默认值 | 描述 |
---|---|---|---|---|
url | String | 是 | 开发者服务器接口地址,url 中不能有端口 | |
data | Object/String/ArrayBuffer | 否 | 请求的参数 | |
header | Object | 否 | 设置请求的 header,header 中不能设置 Referer,content-type 默认为 ‘application/json’; | |
method | String | 否 | GET | (需大写)有效值:OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT |
dataType | String | 否 | json | 如果设为json,会尝试对返回的数据做一次 JSON.parse |
responseType | String | 否 | text | 设置响应的数据类型。合法值:text、arraybuffer |
success | Function | 否 | 调用成功的回调函数 | |
fail | Function | 否 | 调用失败的回调函数 | |
complete | Function | 否 | 调用结束的回调函数(调用成功、失败都会执行) |
3.success返回参数说明
参数 | 类型 | 说明 |
---|---|---|
data | Object/String/ArrayBuffer | 开发者服务器返回的数据 |
statusCode | Number | 开发者服务器返回的 HTTP 状态码 |
header | Object | 开发者服务器返回的 HTTP Response Header |
data数据说明:
最终发送给服务器的数据是 String 类型,如果传入的 data 不是 String 类型,会被转换成 String 。
转换规则如下:
对于 GET 方法的数据,会将数据转换成 query string(encodeURIComponent(k)=encodeURIComponent(v)&encodeURIComponent(k)=encodeURIComponent(v)...)
对于 POST 方法且 header['content-type'] 为 application/json 的数据,会对数据进行 JSON 序列化
对于 POST 方法且 header['content-type'] 为 application/x-www-form-urlencoded 的数据,会将数据转换成 query string (encodeURIComponent(k)=encodeURIComponent(v)&encodeURIComponent(k)=encodeURIComponent(v)...)
4.中断请求任务
返回一个requestTask对象,通过requestTask可中断请求任务;
requestTask对象方法列表:
abort - 中断请求任务;
5.eg
1 | //网络请求 |
四、WebSocket
1.wx.connectSocket - 创建WebSocket连接
返回SocketTask对象,WebSocket任务;
对象方法列表:
SocketTask.send(object) - 通过 WebSocket 连接发送数据。
SocketTask.close(object) - 关闭 WebSocket 连接
SocketTask.onOpen - 监听 WebSocket 连接打开事件
SocketTask.onClose - 监听 WebSocket 连接关闭事件
SocketTask.onError - 监听 WebSocket 错误
SocketTask.onMessage - 监听WebSocket接受到服务器的消息事件
2.wx.onSocketOpen(CALLBACK) - 监听WebSocket连接打开事件
callback回调函数 res header object 连接成功的HTTP响应Header
3.wx.onSocketError(CALLBACK) - 监听WebSocket错误
4.wx.sendSocketMessage(OBJECT) - 通过 WebSocket 连接发送数据
需要先wx.connectSocket,并在wx.onSocketOpen回调之后才能发送;
object参数说明:
参数 | 类型 | 必填 | 描述 |
---|---|---|---|
data | String/ArrayBuffer | 是 | 需要发送的内容 |
success | Function | 否 | 调用成功回调函数 |
fail | Function | 否 | 调用失败回调函数 |
complete | Function | 否 | 调用结束回调函数(不管成功、失败、都执行) |
5.wx.onSocketMessage(CALLBACK) - 监听WebSocket接受到服务器的消息事件
6.wx.closeSocket(OBJECT) - 关闭 WebSocket 连接。
参数 | 类型 | 必填 | 描述 |
---|---|---|---|
code | Number | 否 | 一个数字值表示关闭连接的状态号,表示连接被关闭的原因。如果这个参数没有被指定,默认的取值是1000 (表示正常连接关闭) |
reason | String | 否 | 一个可读的字符串,表示连接被关闭的原因。这个字符串必须是不长于123字节的UTF-8 文本(不是字符) |
success | Function | 否 | 调用成功回调函数 |
fail | Function | 否 | 调用失败回调函数 |
complete | Function | 否 | 调用结束回调函数(不管成功、失败、都执行) |
7.wx.onSocketClose(CALLBACK) - 监听WebSocket关闭
8.注意:
v1.7.0- 小程序同时只能有一个WebSocket连接,如果当前已经存在一个WebSocket连接,会自动关闭该链接,并重新创建一个WebSocket连接;
v1.7.0+ 支持存在多个WebSocket连接,每次成功调用wx.connectSocket会返回一个新的SocketTask;
时序问题:如果 wx.connectSocket 还没回调 wx.onSocketOpen,而先调用 wx.closeSocket,那么就做不到关闭 WebSocket 的目的。
9.eg
1 | //连接 |
参考资料:
1.网络API
一、缓存简介
1.大小:同一个微信号,同一个小程序storage上限10M。
如果用户存储空间不足,会清空最近最久未使用的小程序的本地缓存;
不建议将关键信息全部存在本地缓存,以防存储空间不足或用户更换设备的情况;
2.安全:本地缓存localStorage以用户纬度隔离,同一台设备上,A用户无法读取B用户数据。
3.存储方式:
wx.setStorage(wx.setStorageSync) 写入
wx.getStorage(wx.getStorageSync) 读取指定信息
wx.getStorageInfo(wx.getStorageSync) 读取storage信息
wx.clearStorage(wx.clearStorageSync) 清除
wx.removeStorage(wx.removeStorageSync)清除指定信息
二、写入
1.同步 wx.setStorageSync(key,data)
将数据 同步 存储在本地缓存中指定的key中,会覆盖原来该key对应内容;
2.异步 wx.setStorage(object)
将数据 异步 存储在本地缓存中指定的key中,会覆盖原来该key对应内容;
3.参数说明
参数 | 类型 | 必填 | 描述 |
---|---|---|---|
key | String | 是 | 本地缓存中指定的key |
data | Object/String | 是 | 存储的内容 |
success | Function | 否 | 调用成功的回调函数 |
fail | Function | 否 | 调用失败的回调函数 |
complete | Function | 否 | 调用结束的回调函数(成功、失败都执行) |
4.eg
setStorageAction: function () {
var key = this.data.key
var data = this.data.data
if (key.length === 0) {//key不存在,弹框提示
this.setData({
key: key,
data: data,
'dialog.hidden': false,
'dialog.title': '保存数据失败',
'dialog.content': 'key 不能为空'
})
} else {
//同步 wx.setStorageSync
wx.setStorageSync(key, data)
this.setData({
key: key,
data: data,//String或object
'dialog.hidden': false,
'dialog.title': '存储数据成功'
})
异步 - wx.setStorage
wx.setStorage({
key: key,
data: data,
success: function(res){
console.log('success:' + res.errMsg)
},
fail: function(res){
console.log("fail:" + res)
},
complete: function(res){
console.log('complete:'+ res)
}
})
}
}
三、读取
1.同步wx.getStorageSync(key)
从本地缓存 同步 获取指定key对应的内容;
2.异步wx.getStorage(object)
从本地缓存 异步 获取指定key对应的内容;
3.同步wx.getStorageInfosync
同步 获取当前stroage的相关信息;
4.异步wx.getStorageInfo(object)
异步 获取当前storage的相关信息;
5.参数说明
参数 | 类型 | 必填 | 描述 |
---|---|---|---|
wx.getStorage | |||
key | String | 是 | 本地缓存中的指定的 key |
success | Function | 是 | 调用成功的回调函数,res = {data: key对应的内容} |
fail | Function | 否 | 调用失败的回调函数 |
complete | Function | 否 | 调用结束的回调函数(调用成功、失败都会执行) |
success返回参数描述 | |||
data | String | key对应的内容 | |
wx.getStorageSync | |||
key | String | 是 | 本地缓存中的指定key |
wx.getStorageInfo | |||
success | Function | 是 | 调用成功的回调函数 |
fail | Function | 否 | 调用失败的回调函数 |
complete | Function | 否 | 调用结束的回调函数(调用成功、失败都会执行) |
success返回参数描述 | |||
keys | String Array | 当前storage中所有key | |
currentSize | Number | 当前占用空间的大小,kb | |
limitSize | Number | 限制空间的大小,kb |
6.eg
getStorageAction: function () {
var key = this.data.key,
data = this.data.data
var storageData
if (key.length === 0) {
this.setData({
key: key,
data: data,
'dialog.hidden': false,
'dialog.title': '读取数据失败',
'dialog.content': 'key 不能为空'
})
} else {
//异步获取指定key对应内容
wx.getStorage({
key: key,
success: function(res) {
console.log(res.data)
},
}),
//同步获取指定key对应内容
storageData = wx.getStorageSync(key)
if (storageData === "") {
this.setData({
key: key,
data: data,
'dialog.hidden': false,
'dialog.title': '读取数据失败',
'dialog.content': '找不到 key 对应的数据'
})
} else {
this.setData({
key: key,
data: data,
'dialog.hidden': false,
'dialog.title': '读取数据成功',
'dialog.content': "data: '"+ storageData + "'"
})
}
//同步获取storage内容
try {
var res = wx.getStorageInfoSync()
console.log('getStorageInfoSync:' + res.keys)
console.log('getStorageInfoSync:' + res.currentSize)
console.log('getStorageInfoSync:' + res.limitSize)
} catch (e) {
// Do something when catch error
console.log('error')
}
//异步获取storage内容
wx.getStorageInfo({
success: function(res) {
console.log('getStorageInfo:' + res.keys)
console.log('getStorageInfo:' + res.currentSize)
console.log('getStorageInfo:' + res.limitSize)
},
})
}
}
四、清除
1.同步wx.removeStorageSync(key)
从本地缓存中 同步 移除指定 key
2.异步wx.removeStorage(key)
从本地缓存中 异步 移除指定 key
3.同步wx.clearStorageSync
同步 清理本地数据缓存;
4.异步wx.clearStorage
异步 清理本地数据缓存;
5.参数说明
参数 | 类型 | 必填 | 描述 |
---|---|---|---|
key | String | 是 | 本地缓存中的指定的 key |
success | Function | 是 | 调用成功的回调函数 |
fail | Function | 否 | 调用失败的回调函数 |
complete | Function | 否 | 调用结束的回调函数(调用成功、失败都会执行) |
6.eg
clearStorageAction: function () {
var key = this.data.key,
data = this.data.data
//同步 清理本地数据缓存
wx.clearStorageSync()
this.setData({
key: '',
data: '',
'dialog.hidden': false,
'dialog.title': '清除数据成功',
'dialog.content': ''
})
//异步 清理本地数据缓存
wx.clearStorage()
//从本地缓存中异步移除指定 key
wx.removeStorage({
key: key,
success: function(res) {
console.log(res.data)
}
})
//从本地缓存中同步移除指定 key
try {
wx.removeStorageSync('key')
} catch (e) {
// Do something when catch error
}
}
参考资料:
1.API-数据缓存
一、Audio组件和API
1.属性
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
id | String | audio组件的唯一标志符 | |
src | String | 音频资源地址 | |
loop | Boolean | 是否循环播放 | |
controls | Boolean | 是否显示默认控件 | |
poster | String | 默认控件上音频封面图片资源地址(controls=false,poster无效) | |
name | String | 未知音频 | 默认控件上的音频名字(controls=false,poster无效) |
author | String | 未知作者 | 默认控件上的作者名字(controls=false,poster无效) |
binderror | EvenHandle | 当发生错误时触发 error 事件,detail = {errMsg: MediaError.code} | |
bindplay | EvenHandle | 当开始/继续播放时触发play事件 | |
bindpause | EvenHandle | 当暂停播放时触发 pause 事件 | |
bindtimeupdate | EvenHandle | 当播放进度改变时触发 timeupdate 事件,detail = {currentTime, duration} | |
bindended | EvenHandle | 当播放到末尾时触发 ended 事件 |
2.错误码 MediaError.code
1 - 获取资源被用户禁止
2 - 网络错误
3 - 解码错误
4 - 不合适资源
3.音频组件API
推荐V1.6.0+ wx.createInnerAudioContext()
方法 | 描述 | 只读 | |
---|---|---|---|
src | String | 音频地址,用于直接播放 | |
startTime | Number | 开始播放位置,默认0,单位s | |
autoPlay | Boolean | 默认false | |
loop | Boolean | 是否循环播放,默认false | |
obeyMyteSwitch | Boolean | 是否遵循系统静音开关,false即使用户打开静音开关也能发出声音,默认true | |
duration | Number | 当前音频时长(s),src合法返回 | |
currentTime | Number | 当前音频的播放位置(单位:s),只有在当前有合法的 src 时返回,时间不取整,保留小数点后 6 位 | |
paused | Boolean | 当前是是否暂停或停止状态,true 表示暂停或停止,false 表示正在播放 | |
buffered | Number | 音频缓冲的时间点,仅保证当前播放时间点到此时间点内容已缓冲。 | |
volume | Number | 音量。范围 0~1 |
innerAudioContext 对象的方法列表:
方法 | 参数 | 说明 |
---|---|---|
play | 无 | 播放 |
pause | 无 | 暂停 |
stop | 无 | 停止 |
seek | position | 跳转到指定位置,单位 s |
destroy | 无 | 销毁当前实例 |
onCanplay | callback | 音频进入可以播放状态,但不保证后面可以流畅播放 |
onPlay | callback | 音频播放事件 |
onPause | callback | 音频暂停事件 |
onStop | callback | 音频停止事件 |
onEnded | callback | 音频自然播放结束事件 |
onTimeUpdate | callback | 音频播放进度更新事件 |
onError | callback | 音频播放错误事件 |
onWaiting | callback | 音频加载中事件,当音频因为数据不足,需要停下来加载时会触发 |
onSeeking | callback | 音频进行 seek 操作事件 |
onSeeked | callback | 音频完成 seek 操作事件 |
offCanplay | callback | 取消监听 onCanplay 事件 1.9.0 |
offPlay | callback | 取消监听 onPlay 事件 1.9.0 |
offPause | callback | 取消监听 onPause 事件 1.9.0 |
offStop | callback | 取消监听 onStop 事件 1.9.0 |
offEnded | callback | 取消监听 onEnded 事件 1.9.0 |
offTimeUpdate | callback | 取消监听 onTimeUpdate 事件 1.9.0 |
offError | callback | 取消监听 onError 事件 1.9.0 |
offWaiting | callback | 取消监听 onWaiting 事件 1.9.0 |
offSeeking | callback | 取消监听 onSeeking 事件 1.9.0 |
offSeeked | callback | 取消监听 onSeeked 事件 |
errCode 说明
10001 系统错误
10002 网络错误
10003 文件错误
10004 格式错误
-1 未知错误
不推荐V1.6.0- wx.createAudioContext(audioId, this)
方法 | 参数 | 描述 |
---|---|---|
setSrc | src | 音频地址 |
play | 播放 | |
pause | 暂停 | |
seek | position | 跳转指定位置,单位s |
4.eg
1 | parents.wxml |
1 | parents.js |
二、Video组件和API
1.组件属性
<view>
<view class='title'>1-402前</view>
<video class='video1' src='{{videoSrcFront}}'>视频监控</video>
</view>
<view>
<view class='title'>2-205后</view>
<video class='video2' src='{{videoSrc}}' controls='true' danmu-btn='true' enable-danmu='true' danmu-list='{{list}}'>视频监控</video>
</view>
2.注意
video组件是由客户端创建的原生组件,层级最高,不能通过z-index控制层级;
不能在scroll-view、swiper、picker-view、movable-view中使用;
css动画在video组件中无效;
默认宽度300px、高度225px,可通过wxss设置宽高;
3.API
wx.chooseVideo 拍摄视频或从相册中选视频,返回视频的临时文件路径
wx.saveVideoToPhotosAlbum 保存视频到系统相册,需要用户授权scope.writePhotosAlbum
wx.createVideoCOntext(videoId,this) 创建并返回video上下文videoContext对象
三、camera组件和API
1.属性
属性名 | 类型 | 默认值 | 描述 |
---|---|---|---|
device-postion | String | back | 前置或后置,值为front,back |
flash | String | auto | 闪关灯 值为auto,on,off |
bindstop | EventHandle | 摄像头在非正常终止时触发,如退出后台等情况 | |
binderror | EventHandle | 用户不允许使用摄像头时触发 |
2.注意
camera组件是由客户端创建的原生组件,层级最高,不能通过z-index控制层级,可使用cover-view、cover-image覆盖在上面;
不能在scroll-view、swiper、picker-view、movable-view中使用;
同一页面只能插入一个camera组件;
3.API
wx.createCameraContext(this) 创建并返回 camera 上下文 cameraContext 对象,cameraContext 与页面的 camera 组件绑定,一个页面只能有一个camera,通过它可以操作对应的 <camera/> 组件;
cameraContext对象方法:
takePhoto - 拍照
startRecord - 开始录像
stopRecord - 结束录像
4.eg
1 |
|
四、image组件和API
1.属性
属性名 | 类型 | 默认值 | 描述 |
---|---|---|---|
src | String | 图片资源地址 | |
mode | String | ‘scaleToFill’ | 图片裁剪、缩放的模式 |
lazy-load | Boolean | false | 图片懒加载。针对page与scroll-view下的image有效 |
binderror | HandleEvent | 当错误发生时,发布到 AppService 的事件名,事件对象event.detail = {errMsg: ‘something wrong’} | |
bindload | HandleEvent | 当图片载入完毕时,发布到 AppService 的事件名,事件对象event.detail = {height:’图片高度px’, width:’图片宽度px’} | |
mode值 | mode13种模式(4中缩放,9种裁剪) | ||
缩放 | scaleToFill | 不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素 | |
缩放 | aspectFit | 保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。 | |
缩放 | aspectFill | 保持纵横比缩放图片,只保证图片的短边能完全显示出来. | |
缩放 | widthFix | 宽度不变,高度自动变化,保持原图宽高比不变 | |
裁剪 | top | …顶部… | |
裁剪 | bottom | …底部… | |
裁剪 | center | …中间… | |
裁剪 | left | …左边… | |
裁剪 | right | …右边… | |
裁剪 | top left | …左上… | |
裁剪 | top right | …右上… | |
裁剪 | bottom let | …左下… | |
裁剪 | bottom right | …右下… |
2.注意
image默认组件width=300px,height=225px;
文件的临时路径,在小程序本次启动期间可以正常使用,如需持久保存,需在主动调用 wx.saveFile,在小程序下次启动时才能访问得到;
3.API
wx.chooseImage 从相册选择图片或使用相机拍照;
wx.previewImage 预览图片;
wx.getImageInfo 获取图片信息;
wx.saveImageToPhotosAlbum 保存图片到系统相册;
4.eg
1 | <image class='background' style="width: 100%; height: 100%;" src='../../../images/bg.png'></image> |
五、录音
1.推荐API - v1.6.0+
wx.getRecorderManager() 获取全局唯一的录音管理器 recorderManager
recorderManager对象方法列表
方法 | 参数 | 描述 |
---|---|---|
start | options | 开始录音 |
pause | 暂停录音 | |
resume | 继续录音 | |
stop | 停止录音 | |
onStart | callback | 录音开始事件 |
onPause | callback | 录音暂停事件 |
onStop | callback | 录音停止事件,会回调文件地址 |
onFrameRecorded | callback | 已录制完指定帧大小的文件,会回调录音分片结果数据,如果设置了frameSize,则会回调此事件 |
onError | callback | 录音错误事件,会回调错误信息 |
2.不推荐API - v1.6.0-
wx.startRecord
需要用户授权scope.record;
用户离开小程序无法调用此API;
wx.stopRecord
自动调用结束或者录音超过1分钟,自动结束录音;
返回录音文件的临时文件路径;
文件的临时路径,在小程序本次启动期间可以正常使用,如需持久保存,需在主动调用 wx.saveFile,在小程序下次启动时才能访问得到;
3.eg
1 | v1.6.0+方法 |
六、音频播放控制
1.推荐API - v1.6.0+
wx.createInnerAudioContext() 创建并返回内部 audio 上下文 innerAudioContext 对象
2.不维护API - v1.6.0-
wx.playVoice() 开始播放语音
同时允许一个语音文件正在播放,如果前一个语音文件未播放完,将中断前一个语音播放;
wx.pauseVoice() 暂停播放语音
再次调用wx.playVoice播放同一个文件时,会从暂停处开始播放;
如果想从头开始播放,需先调用wx.stopVoice();
wx.stopVoice() 结束播放语音
七、音乐播放控制(背景音频播放管理)
1.推荐API - v1.2.0+
wx.getBackgroundAudioManager() 获取全局唯一的背景音频管理器 backgroundAudioManager
backgroundAudioManager 对象属性列表
duration 当前音频的长度(单位:s),只有在当前有合法的 src 时返回
currentTime 当前音频的播放位置(单位:s),只有在当前有合法的 src 时返回
paused
src 音频的数据源,默认为空字符串,当设置了新的 src 时,会自动开始播放 ,目前支持的格式有 m4a, aac, mp3, wav
startTime
buffered 音频缓冲的时间点,仅保证当前播放时间点到此时间点内容已缓冲
title
epname
singer
coverImgeUrl 封面图url,用于做原生音频播放器背景图。原生音频播放器中的分享功能,分享出去的卡片配图及背景也将使用该图
webUrl 页面链接,原生音频播放器中的分享功能,分享出去的卡片简介,也将使用该值
protocol 音频协议。默认值为 'http',设置 'hls' 可以支持播放 HLS 协议的直播音频
对象方法列表:
play
pause
stop
seek
onCanplay 背景音频进入可以播放状态,但不保证后面可以流畅播放
onPause
onStop
onEnded
onTimeUpdate 背景音频播放进度更新事件
onPrev 用户在系统音乐播放面板点击上一曲事件(iOS only)
onNext 用户在系统音乐播放面板点击下一曲事件(iOS only)
onError
onWaiting 音频加载中事件,当音频因为数据不足,需要停下来加载时会触发
错误码
10001 系统错误
10002 网络错误
10003 文件错误
10004 格式错误
-1 未知错误
2.不维护API - v1.2.0-
wx.getBackgroundAudioPlayerState() 获取后台音乐播放状态
wx.playBackgroundAudio() 使用后台播放器播放音乐
对于微信客户端来说,只能同时有一个后台音乐在播放。
当用户离开小程序后,音乐将暂停播放;
当用户点击“显示在聊天顶部”时,音乐不会暂停播放;
当用户在其他小程序占用了音乐播放器,原有小程序内的音乐将停止播放.
wx.pauseBackgroundAudio() 暂停播放音乐
wx.seekBackgroundAudio() 控制音乐播放进度
iOS 6.3.30 会有短暂延迟
wx.stopBackgroundAudio() 停止播放音乐
wx.onBackgroundAudioPlay(CALLBACK) 监听音乐播放。
wx.onBackgroundAudioPause(CALLBACK) 监听音乐暂停。
wx.onBackgroundAudioStop(CALLBACK) 监听音乐停止。
八、实时音视频播放
wx.createLivePlayerContext(domId, this)
操作对应的 <live-player/> 组件。 创建并返回 live-player 上下文 LivePlayerContext 对象。在自定义组件下,第二个参数传入组件实例this,以操作组件内 <live-player/> 组件
livePlayerContext 对象的方法列表
play 播放
stop 停止
mute 静音
pause 暂停
resume 恢复
requestFullScreen 进入全屏
exitFullSrceen 退出全屏
wx.createLivePusherContext()
创建并返回 live-pusher 上下文 LivePusherContext 对象,LivePusherContext 与页面的 <live-pusher /> 组件绑定,一个页面只能有一个 live-pusher,通过它可以操作对应的 <live-pusher/> 组件。 在自定义组件下,第一个参数传入组件实例this,以操作组件内 <live-pusher/> 组件
livePusherContext 对象的方法列表
start 开始推流
stop 停止推流
pause 暂停推流
resume 恢复推流
switchCamera 切换前后摄像头
snapshot 快照
参考资料:
1.Audio
2.音频组件API
3.音频进度条
4.image组件
5.imageAPI
6.Camera组件和API
7.录音
8.语音播放控制
9.实时音视频
一、需求描述
在入口处有三个角色,点击不同的角色在Tabbar上显示不同的内容(pagPpath、text、iconPath、selectedIconPath):
二、解决方案:
1.自定义Tabbar模版
1.自定义TabBar模版;
2.app.json中不做“tabBar”的配置;
3.app.wxss中修改自定义模版样式:
.menu-item{
width: 24%;
float: left;
text-align: center;
padding-top: 8px;
}
.img{
width: 23px;
height: 23px;
display: block;
margin:auto;
}
.clear{
clear: both;
}
.tab-bar{
width:100%;
position: fixed;
bottom:0;
padding:10rpx;
/* margin-left:-4rpx; */
background:#F7F7FA;
font-size:20rpx;
color:#8A8A8A;
/* box-shadow: 6rpx 6rpx 6rpx 6rpx #aaa; */
height: 40px;
/* position: fixed;
width: 100%;
padding: 0px 2%;
height: 50px;
background: rgb(247, 247, 250);
font-size: 20rpx; */
}
4.app.js中:
globalData:{
userInfo: null,
userRole: "-1",//1-家长 2-教师 3-管理员|学校
...
tabBarParent:{
"color": "#9e9e9e",
"selectedColor": "#33cbd5",
"postion": "bottom",
"backgroundColor": "#fff",
"borderStyle": "#ccc",
“list”:
[{
"pagePath": "/pages/home/home",
"text": "学校",
"iconPath": "/pages/images/home.png",
"selectedIconPath": "/pages/images/home-sel.png",
"selectedColor": "#4EDF80",//配置选中字体颜色
"clas": "menu-item",
active: false
},
{
通讯录
...
"clas": "menu-item",
active: false
},
{班级圈...},
{我的...}]
},
tabBarTeacher:{//图标和家长端不一样,pagePath不一样
"color": "#9e9e9e";
...
“list”:
[{ 学校
"clas": "menu-item1",
active: false
},
{通讯录},
{班级圈},
{我}]
},
tabBarAdmin:{//图标和家长端不一样,pagePath不一样
"color": "#9e9e9e";
...
“list”: [
{学校},{信箱},{学校公告},{中心}
]
},
}
4.app.js中重写系统方法:
//重写家长中心
updateTabBarParent:funcation() {
var _curPageArr = getCurrentPages();
var _curPage = _curPageArr[_curPageArr.length - 1];
var _pagePath = _curPage.__route__;
if (_pagePath.indexOf('/') != 0) {
_pagePath = '/' + _pagePath;
}
var tabBar = this.globalData.tabBarParent;//获取家长Tabbar数组数据
for (var i = 0; i < tabBar.list.length; i++) {
tabBar.list[i].active = false;
if (tabBar.list[i].pagePath == _pagePath) {
tabBar.list[i].active = true;//根据页面地址设置当前页面状态
}
}
_curPage.setData({
tabBar: tabBar
});
}
//重写教师中心
updateTabBarTeacher:funcation() {
...
}
//重写管理中心
updateTabBarAdmin:funcation() {
...
}
5.设置入口角色
index.html
<view class="container">
<view class='button' bindtap='clickParent'>家长中心</view>
<view class='button' bindtap='clickTeacher'>教师中心</view>
<view class='button' bindtap='clickAdmin'>管理中心</view>
</view>
index.js
clickParent: function(){
console.log("家长");
getApp().globalData.userRole = "1"
wx.redirectTo({
url: '../parent/parent',
})
},
clickTeacher: function(){
console.log("教师");
getApp().globalData.userRole = "2"
wx.redirectTo({
url: '../teach/teach',
})
},
clickAdmin: function(){
console.log("管理");
getApp().globalData.userRole = "3"
wx.redirectTo({
url: '../admin/admin',
})
},
6.在相关模块文件xx..wxml中导入模版:
eg:home.wxml
<import src="../template/template.wxml"/> <template is="tabBar" data="{{tabBar}}"/>
7.在相关模块文件xx.js中刷新tabBar:
eg:home.js
const app = getApp()
Page({
...
onLoad:function (option){
if (getApp().globalData.userRole === "1") {
app.updateTabBarWithParent();
}
if (getApp().globalData.userRole === "2") {
app.updateTabBarWithTeacher();
}
if (getApp().globalData.userRole === "3") {
app.updateTabBarWithAdmin();
}
}
...
})
2.定义变量,配置变量(
app.json配置
{
"pages": [
...
],
"window": {
...
},
"tabBar": {
"color": "#6e6d6b",
"selectedColor": "#33cbd5",
"list": [{
"pagePath": "pages/common/home/home",
"text": "学校",
"iconPath": "pages/images/nav/home.png",//默认图标
"selectedIconPath": "pages/images/nav/home-sel.png"//选中图标
},
...
}
}
参考资料:
1.自定义Tabbar模版
2.官网Tabbar组件
3.自定义Tabbar
方法一:WinPE清除密码
1.PE盘启动电脑;
2.C盘:windows/system32下:
更改Magnify.exe 和cmd.exe的所有者: administrators;
更改Magnify.exe 和cmd.exe的权限 administrators 为完全控制;
改名Magnify.exe-->Magnify.exe1
cmd.exe-->Magnify.exe
3.更改密码
重启Win7;
启用放大镜;
命令:
net user(查看用户名)
net user 用户名新密码
激活管理员账号使用: net user administrator /active:yes
改回之前改动的操作
方法二:重装系统
tips:
1.U盘启动工具制作;
老毛桃
雨林木风
2.U盘重装系统;
参考值资料:
1.WinPE清除密码
2.Win7找回密码
3.破解系统密码
4.管理员密码破解
5.重置密码-错误警告
6.windows管理员密码破解
tag:
缺失模块。
1、请确保node版本大于6.2
2、在博客根目录(注意不是yilia根目录)执行以下命令:
npm i hexo-generator-json-content --save
3、在根目录_config.yml里添加配置:
jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true