# data_visual_bluetooth
**Repository Path**: jiaqinbi/data_visual_bluetooth
## Basic Information
- **Project Name**: data_visual_bluetooth
- **Description**: 微信小程序,功能包含蓝牙扫描连接、数据可视化(echarts)。仅供个人交流学习使用。
- **Primary Language**: JavaScript
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 3
- **Forks**: 3
- **Created**: 2021-07-09
- **Last Updated**: 2024-05-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
以下文档为开发指南,请点击[使用指南](user_guide.md)
# 一、准备工作
## 1、注册开发者账号(小程序)
1. 首先进入微信公众平台进行注册,网址如下:https://mp.weixin.qq.com/

2. 使用邮箱进行注册,邮箱必须是没有在微信公众平台注册过的。如下所示:
3. 收到激活邮件,进行激活,如下所示:

4. 主题选择个人时需要填写主体信息(包括姓名、身份证号码、手机号码),填写完成后需使用手机号绑定的微信号扫码确认,并进一步弹窗确认。如下所示:

5. 确定后,进入微信公众平台-小程序首页,可以看见小程序发布流程,如下所示:

## 2、下载开发工具
下载网址:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html
一般选择稳定版,如下所示:

## 3、总结
1和2做完之后用户便拥有了自己`AppID`和开发者工具,在第二章中会进行小程序创建和配置的介绍。
# 二、创建工程
打开微信开发者工具,微信扫描进行账号登录。
## 1、创建步骤
新建工程,如下所示:

在上图中填入项目名称、路径、第一章第一节中申请到的`AppID`。后端服务选择本地开发,使用`javascript`。使用云开发与不使用云开发的区别此处不做介绍。
创建完成之后,首页如下所示:

顶部工具栏可以选择编译以及调试模式,使用`windows`开发蓝牙小程序必须使用手机进行调试。

## 2、预览与真机调试的区别
预览与真机调试的区别:
- 预览直接在手机上预览使用,电脑上无法查看输出信息;
- 真机调试时手机上的输出可以在电脑上显示,同时可以命令交互,但是与电脑模拟的区别就是手机调试时可能出现卡顿延迟。
## 3、工程结构介绍
```python
工程名/
| -- pages/ #页面文件
| | -- index/ #页面1---index
| | |-- index.js #index页面的后台函数文件
| | |-- index.json #inedx页面的配置文件
| | |-- index.wxml #index页面的UI设计标签文件
| | |-- index.wxss #index页面的渲染文件
| | -- log/ #页面2---log
| | |-- log.js
| | |-- log.json
| | |-- log.wxml
| | |-- log.wxss
| -- utils/ #自动生成
| | -- utils.js #公用的工具相关代码文件
| -- app.js #全局js文件
| -- app.json #全局配置文件
| -- app.wxss #全局页面渲染文件
| -- project.config.json #工程配置文件,包括AppID
| -- sitemap.json #基本没用到
```
## 4、工程配置
在`app.json`中的`appid`属性中可以配置自己的`AppID`,如果前期创建的工程使用的是测试号就可以通过此属性进行绑定。
其它配置属性较多,用到时再进行相关介绍,也可参考官网[全局与页面配置](https://developers.weixin.qq.com/miniprogram/dev/framework/config.html)
## 5、新建页面
1. 方式一
在全局`app.json`中的pages属性中按照格式填写需要添加的页面,首页放在最开始,填写完成保存之后会自动创建添加页面的所有文件。
如创建一个data页面放在首页,代码如下所示:
```json
"pages":[
"pages/data/data",
"pages/index/index",
"pages/logs/logs"
],
```
添加完成之后保存会自动编译运行,也可以点击顶部编译按钮运行,可以看到默认页面效果和添加的文件。如下所示:

2. 方式二(不推荐)
手动在`pages`文件夹下一一创建文件。
**注**:后续所有新建的页面都保存在pages目录下(当然也可以自己新建,但为了清晰的目录结构一般新建的页面都保存在`pages`下)。
注意小程序开发过程中使用真机模拟时需保持电脑联网。
## 6、语言介绍
1. 页面布局:页面布局使用的标签语言,与`HTML`(超文本标记语言)类似;
语法参考官网[WXML语法参考](https://developers.weixin.qq.com/miniprogram/dev/reference/wxml/)
2. 页面样式:页面的样式表使用的也是层叠样式表,与`CSS`类似;
语法参考官网[WXS语法参考](https://developers.weixin.qq.com/miniprogram/dev/reference/wxs/)
3. 功能函数:写功能函数的语言是`javascript`,是脚本语言;
语法通用,可参考菜鸟教程[菜鸟javascript教程](https://www.runoob.com/js/js-tutorial.html)
# 三、TabBar的使用
## 1、TabBar的介绍
`tabBar`可以实现类似微信底部的菜单显示和切换效果。
## 2、 自定义 TabBar
自定义 `tabBar `可以让开发者更加灵活地设置 `tabBar `样式,以满足更多个性化的场景。开发步骤如下:
1. 在 `app.json` 中的 `tabBar` 项指定 `custom` 字段,同时其余 `tabBar` 相关配置也补充完整。
2. 所有 tab 页的 json 里需声明 `usingComponents` 项,也可以在 `app.json` 全局开启。
**==注意==**:自行编写时将`custom`修改为true时不显示`tabbar`,所以本次采用2中的前一个方法,局部开启。
效果如下所示:

## 3、TabBar的升级
一般有些底部工具栏中间的一部分会凸起,比如本项目中的蓝牙设备连接,先看例子

开发步骤如下:
1. 复制网上提供的`custom-tab-bar`自定义工具栏代码至到项目根目录。
2. `app.json中tabBar`不变,打开`custom-tab-bar/index.js`,按照格式修改`list`下的列表文件,注意最中间显示的需要凸起的项中`text`删去,加入配置`bulge:true`。
3. 依次打开每个`tabBar`列表中的`js`文件,从左往右数,下标第一个是0,第二个是1,依次往后(4中需要用到)。
4. 每个`tabBar`列表中的js文件中的生命周期函数`onShow`中加入如下代码(下标为3中提到的下标):
```javascript
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setData({
selected: 下标
})
}
},
```
5. 至此修改结束
# 四、蓝牙连接
## 1、官方demo
请点击[官方demo](https://developers.weixin.qq.com/s/pQU51zmz7a3K)进行预览(需安装微信开发者工具)。
## 2、方法介绍
### openBluetoothAdapter
**功能**:初始化蓝牙模块。
代码如下所示:
```js
/**
* 打开蓝牙适配器
*/
openBluetoothAdapter() {
wx.openBluetoothAdapter({ //判断蓝牙是否打开
success: (res) => {
console.log('蓝牙适配器已打开', res)
this.startBluetoothDevicesDiscovery()
},
fail: (res) => {
if(res)
wx.showModal({
showCancel: false, //不显示取消按钮
content: '请先开启手机蓝牙,然后重试!'
})
}
})
}
```
### startBluetoothDevicesDiscovery
**功能**:扫描附近的蓝牙外围设备。此操作比较耗费系统资源,连接到设备后可即刻停止搜索。
代码如下所示:
```js
/**
* 蓝牙扫描
*/
startBluetoothDevicesDiscovery() {
if (this._discoveryStarted) {
return
}
this._discoveryStarted = true //第一次点击扫描之后设置为true,防止重复点击
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: true, //允许重复上报同一设备
interval:0, //上报设备的间隔。0 表示找到新设备立即上报,其他数值根据传入的间隔上报
powerLevel: "high", //扫描模式,越高扫描越快,且越耗电
success: (res) => {
console.log('开始搜寻蓝牙设备', res)
this.setData({
scan_status: true,
btn_scan_name: '正在扫描',
btn_kill_service_status: false,
})
this.onBluetoothDeviceFound()
},
})
}
```
### onBluetoothDeviceFound
**功能**:监听寻找到新设备的事件。
代码如下所示:
```js
/**
* 监听蓝牙设备 并回调
*/
onBluetoothDeviceFound() {
wx.onBluetoothDeviceFound((res) => {
//将查找到的蓝牙名称加入到数组中
res.devices.forEach(device => {
all_devices[device.deviceId] = device.name
if (!device.name && !device.localName) {
return
}
const foundDevices = this.data.devices
const idx = inArray(foundDevices, 'deviceId', device.deviceId)
const data = {}
if (idx === -1) {
data[`devices[${foundDevices.length}]`] = device
} else {
data[`devices[${idx}]`] = device
}
this.setData(data)
this.setData({
bluetooth_list: all_devices,
})
})
})
}
```
### createBLEConnection
**功能**:连接低功耗蓝牙设备。若小程序在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 `deviceId `直接尝试连接该设备,无需进行搜索操作。
代码如下所示:
```js
/**
* 蓝牙连接
* @param {*} e
*/
createBLEConnection(e) {
const ds = e.currentTarget.dataset
const deviceId = ds.deviceId //uuid
const name = ds.name
wx.createBLEConnection({
deviceId,
success: (res) => {
wx.showToast({
title: '连接成功',
duration:500, //提示延迟时间
})
app.globalData.bluet_conn_flag = true,
this.getBLEDeviceServices(deviceId) //获取 Service UUID
this.setData({
bluet_conn_flag: true, //蓝牙连接成功
name,
deviceId,
//改变按钮状态
btn_scan_status: true,
btn_stop_scan_status: true,
btn_conn_status: false,
})
this.stopBluetoothDevicesDiscovery() //连接之后停止蓝牙搜索
},
fail(e) {
... //省略
}
})
}
```
### getBLEDeviceServices
**功能**:获取蓝牙设备所有服务(service),即`服务UUID`。
代码如下所示:
```js
/**
* 获取 service UUID
* @param {*} deviceId
*/
getBLEDeviceServices(deviceId) {
wx.getBLEDeviceServices({
deviceId,
success: (res) => {
let serviceUUIDs = new Array() //存储服务UUID
console.log('deviceId:'+deviceId)
console.log('res.services.length:'+res.services.length) //3个service uuid
for (let i = 0; i < res.services.length; i++) {
console.log('res.services['+i+'].uuid: '+res.services[i].uuid)
if (res.services[i].isPrimary) { //判断服务是否为主服务
serviceUUIDs.push(res.services[i])
}
}
this.setData({
serviceUUIDs: serviceUUIDs
})
//监听特性值,通过服务UUID选择监听
this.getBLEDeviceCharacteristics(deviceId, res.services[this.data.leftPosition].uuid,this.data.leftPosition)
},
fail: (res) => {
...//省略
}
})
}
```
### getBLEDeviceCharacteristics
**功能**:获取蓝牙设备某个服务中所有特征值(characteristic),即`特性UUID`。
代码如下所示:
```js
/**
* 获取蓝牙特性UUID信息
* @param {*} deviceId
* @param {*} serviceId
* @param {*} lastPosition
*/
getBLEDeviceCharacteristics(deviceId, serviceId, lastPosition) {
wx.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: (res) => {
let characteristicUUIDs = new Array()
//将某个服务下的特性UUID添加到数组中
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i]
characteristicUUIDs.push(item)
}
this.setData({
characteristicUUIDs: characteristicUUIDs
})
},
fail(res) {
... //省略
}
})
}
```
### onBLECharacteristicValueChange
**功能**:监听低功耗蓝牙设备的特征值变化事件。必须先启用 `notifyBLECharacteristicValueChange` 接口才能接收到设备推送的 `notification`。
代码如下:
```js
//判断本次监听的特性值是否支持读写
if (properties.indicate || (properties.notify && properties.read && properties.write)) {
app.globalData.characterRWN_conn_flag = true
that.setData({
canWrite: true,
characterRWN_conn_flag: true,
characterRWN_UUID: characteristicId,
serviceRWN_UUID: serviceId,
})
wx.notifyBLECharacteristicValueChange({
deviceId,
serviceId,
characteristicId,
state:true,
success(res) {
console.log('notifyBLECharacteristicValueChange success', res.errMsg)
}
})
}else{
wx.showToast({
title: '此服务不支持读写!',
icon:'error',
duration:1500, //提示延迟时间
})
}
//notifyBLECharacteristicValueChange函数监听之后就可以接收数据
wx.onBLECharacteristicValueChange(function (res) {
let hexStr = ab2hex(res.value) //ab2hex函数是将接收到数据转化成十六进制
that.setData({
receive_data: that.hexCharCodeToStr(hexStr),
})
}
```
### wx.closeBluetoothAdapter
**功能**:关闭蓝牙模块。调用该方法将断开所有已建立的连接并释放系统资源。建议在使用蓝牙流程后,与 wx.openBluetoothAdapter 成对调用。
代码如下:
```js
wx.closeBluetoothAdapter({
success (res) {
//关闭蓝牙的一些处理
}
})
```
## 3、连接流程
1. 打开蓝牙
2. 扫描蓝牙设备
3. 连接蓝牙,保存`设备ID`和`服务UUID`
4. 根据每个`服务UUID`监听其对应的`特性UUID`
5. 判断每个`特性UUID`的属性是否支持读写
6. 功能建立能够读写的设备之后便可以进行设备的`特征值`监听。
# 五、数据可视化(ECharts)
## 1、准备工作
1、[ECharts官网](https://echarts.apache.org/zh/tutorial.html#%E5%9C%A8%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%B8%AD%E4%BD%BF%E7%94%A8%20ECharts)
2、[插件下载](https://github.com/ecomfe/echarts-for-weixin)
3、复制`\ec-canvas`文件夹到微信小程序项目的根文件目录
## 2、配置
在对应需要引入`echart`的`page`下的`json`文件中加入配置项,如下
```json
"usingComponents": {
"ec-canvas": "../../ec-canvas/ec-canvas"
}
```
**注意**:此配置项只能在对应需要引入`echart`的`page`中的`json`文件中加入,在全局的`app.json`中加入无效!
## 3、简单示例
**注意**:以下例子以`pages/data/data`页面为例
1、`wxml`文件中 页面布局代码如下
```html
```
2、`wxss`文件中 样式表代码如下
```css
.container {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
}
ec-canvas {
width: 100%;
height: 100%;
}
```
3、`js`文件中 脚本如下
```js
//1 引入echarts
import * as echarts from '../../ec-canvas/echarts';
const app = getApp();
//2 初始化图表函数
function initChart(canvas, width, height, dpr) {
const chart = echarts.init(canvas, null, {
width: width,
height: height,
devicePixelRatio: dpr // new
});
canvas.setChart(chart);
var option = {
title: {
text: '测试下面legend的红色区域不应被裁剪',
left: 'center'
},
color: ["#37A2DA", "#67E0E3", "#9FE6B8"],
legend: {
data: ['A', 'B', 'C'],
top: 50,
left: 'center',
backgroundColor: 'red',
z: 100
},
grid: {
containLabel: true
},
tooltip: {
show: true,
trigger: 'axis'
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
// show: false
},
yAxis: {
x: 'center',
type: 'value',
splitLine: {
lineStyle: {
type: 'dashed'
}
}
// show: false
},
series: [{
name: 'A',
type: 'line',
smooth: true,
data: [18, 36, 65, 30, 78, 40, 33]
}, {
name: 'B',
type: 'line',
smooth: true,
data: [12, 50, 51, 35, 70, 30, 20]
}, {
name: 'C',
type: 'line',
smooth: true,
data: [10, 30, 31, 50, 40, 20, 10]
}]
};
chart.setOption(option);
return chart;
}
Page({
onShareAppMessage: function (res) {
return {
title: 'ECharts 可以在微信小程序中使用啦!',
path: '/pages/data/data',
success: function () { },
fail: function () { }
}
},
data: {
ec: {
onInit: initChart
}
},
onReady() {
}
});
```
4、效果如下所示

## 4、**==引入动态数据==**
### 思路
大体上采用定时器实现
1. 考虑需要显示的数据点的个数
2. 创建一个定长数组,采用队列的形式存入最新的数值
3. 创建一个定时器,定时更新数据
4. 定时更新曲线上的数据
### 具体实现
1、创建数组,代码如下所示
```js
/*
* 以下代码均写在Page外面,以保证最先执行
*/
var length = 7 //坐标轴上数据点的个数
var array_data1 = [length]; //长度为7的数组
```
2、创建更新数组的函数,代码如下所示
```js
/*
* 以下代码均写在Page外面,以保证最先执行
*/
function addData(shift) {
//加入数据
array_data1.push(Math.random()*30 + 0);
if (shift) {
array_data1.shift();//删除当前数组第一个数据
}
}
//首次初始化填充数组
for (var i = 0; i < length; i++) {
addData();
}
```
3、创建定时器更新数据,代码如下所示
```js
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
setInterval(() => {
addData(true)
chart.setOption({
series: {
data: array_data1
},
});
},1000)
},
```
在生命周期中进行更新,当然也可以在`onShow`等其它函数中定时更新,但是必须保证此函数在页面首次加载时会执行一次。
4、更新数据
- 将例子中的`initChart()`函数中的`chart`修改成全局变量,保证定时器可得到此变量
- 修改`series`中的`data`属性值为`array_data1`,如下所示
```js
series: [{
name: 'A',
type: 'line',
smooth: true,
//data:[12, 50, 51, 35, 70, 30, 20]
data: array_data1
}]
```
### 总结与演示
至此,动态数据添加完毕,然后横坐标需要动态修改和上面类似。效果如下所示
## 5、样式表的使用
### 横坐标45°显示以及间隔显示
```js
axisLabel: {
interval:0, //X轴不间隔显示,没有此属性的时候间隔显示是因为X轴每个点的名称太长,设置为1则表示间隔一个显示,以此类推
rotate:45, //代表逆时针旋转45度
}
```
### 横坐标不从零刻度开始
在`xAxis`中加入`boundaryGap`属性,并设置为`true`
### 曲线上显示数据点
在`series`中加入`itemStyle`属性,如下所示
```js
//折线图上显示数据点
itemStyle: {
normal: {
label: {
show: true
}
}
}
```
柱状图和上面一样。
### 修改图表样式
如曲线图修改为柱状图,只需修改`series`中的`type`属性为`bar`即可。
line为折线图,bar为柱状图,具体的可以进[echart官网](https://echarts.apache.org/zh/index.html)查询。
### 修改曲线上数据点圆圈的大小
在`series`中加入`symbolSize: 10`,10表示折线点上小圆圈的大小
### 图例修改
```js
legend: {
// icon: 'rect', //提供'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow', 'none'
itemWeight: 7, //修改icon图形大小
textStyle: {
fontSize: 13,
color: '#000'
},
show:true, //是否显示图例
type:"plain", //图例样式
data: array_dataName,
// top: '3%',
right:'7%',
// left: 'right',
orient: 'vertical',
z: 100
},
```
## 6、问题以及解决方法
### 真机模拟时画面不清晰
此问题在苹果7上测得发现!
可以通过获取像素比的方法清晰化,代码如下所示
```js
//获取像素比
const getPixelRatio = () => {
let pixelRatio = 0
wx.getSystemInfo({
success: function (res) {
pixelRatio = res.pixelRatio
},
fail: function () {
pixelRatio = 0
}
})
return pixelRatio
}
```
然后在`echarts.init`中给属性`devicePixelRatio`设置像素比,代码如下所示
```js
var dpr = getPixelRatio()
const chart = echarts.init(canvas, null, {
width: width,
height: height,
devicePixelRatio: dpr
});
```
### EChart层级过高覆盖其它组件
通过修改`Echart `所在`view`的`top`或者`bottom`来调整距离。
# 六、Picker与showToast
## 1、picker组件
picker组件为从底部弹起的滚动选择器。
[官方picker](https://developers.weixin.qq.com/miniprogram/dev/component/picker.html)
[博客园picker参考](https://www.cnblogs.com/mibear/p/8051370.html)
效果如下,点击按钮时从底部弹出选择器:
## 2、消息提示组件
1. showToast
[showToast官方文档](https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.showToast.html)
# 七、蓝牙开发知识
## 1、UUID
`UUID`可以简单理解为编号,唯一的编号,用于区分不同的个体。服务和特性都有各自的UUID。 
上图中的`Read`, `Notify`,`Write_Without_Response`为该`Characteristic UUID`所具有的属性
## 2、服务UUID(Service UUID)
服务(Service)可以理解为组长,一个组里面至少有一个或多个特性(Characteristic),特性(Characteristic)可以理解为组员。不同的服务(Service)应该有不同的编号(UUID),用以区分不同的服务(Service)。
## 3、特性UUID(Characteristic UUID)
特性(Characteristic)是依附于某个服务(Service)的,可以理解为组员,每个组员至少要有一个编号(UUID)以及一个或多个属性(Property)每个特性(Characteristic)可以同时有一个或多个属性。
## 4、属性(Property)
**==Read==**: 读属性,具有该属性的UUID 是可读的,也就是说这个属性允许手机来读取一些信息。手机可以发送这个指令来读取某个具有读属性UUID的信息,华茂的模块在读取的时候,会返回模块的蓝牙地址。
**==Notify==**: 通知属性, 具有该属性的 UUID是可以发送通知的,也就是说具有这个属性的特性(Characteristic)可以主动发送信息给手机。举个栗子,华茂蓝牙模块发送数据给手机,就是通过这个属性。
**==Write==**: 写属性, 具体该属性的 UUID 是可以接收写入数据的。通常手机发送数据给蓝模块就是通过这个属性完成的。这个属性在Write 完成后,会发送写入完成结果给手机,然后手机再可以写入下一包,这个属性在写入一包数据后,需要等待应用层返回写入结果,速度比较慢。
**==WriteWithout Response==**:写属性,从字面意思上看,只是写,不需要返回写的结果,这个属性的特点是不需要应用层返回,完全依靠协议层完成,速度快,但是写入速度超过协议处理速度的时候,会丢包。华茂的蓝牙模块,Read(读)和Notify(通知)是固定的属性,不能移除和修改,您可以根据需要配置Write(写)的属性。
## 5、错误码
| 错误码 | 错误信息 | 说明 |
| :----- | :------------------- | :-------------------------------------------- |
| 0 | ok | 正常 |
| -1 | already connet | 已连接 |
| 10000 | not init | 未初始化蓝牙适配器 |
| 10001 | not available | 当前蓝牙适配器不可用 |
| 10002 | no device | 没有找到指定设备 |
| 10003 | connection fail | 连接失败 |
| 10004 | no service | 没有找到指定服务 |
| 10005 | no characteristic | 没有找到指定特征值 |
| 10006 | no connection | 当前连接已断开 |
| 10007 | property not support | 当前特征值不支持此操作 |
| 10008 | system error | 其余所有系统上报的异常 |
| 10009 | system not support | Android 系统特有,系统版本低于 4.3 不支持 BLE |
| 10012 | operate time out | 连接超时 |
| 10013 | invalid_data | 连接 deviceId 为空或者是格式不正确 |
在`devConn.js`中的`item.properties.notify || item.properties.indicate`会进行判断特征值是否支持数据通信。
# 八、问题及解决方法
## 1、Cannot read property 'xxx' of null
有些函数在调用的时候会出现题中错误,如果是用this调用的话,则通过`var that=this`,然后用`that.函数名`调用。
## 2、不支持空格` `
设置`decode ="true"`,默认为false
## 3、禁止页面整体上下滚动
在需要禁止的页面的page下的json配置文件中加入`disableScroll":true`,如在data.json下
```json
{
"navigationBarTitleText": "实时数据",
"disableScroll":true
}
```
## 4、页面切换后自动刷新数据
```js
setInterval(() => {
this.setData({
bluet_conn_flag: app.globalData.bluet_conn_flag,//蓝牙连接状态
receive_data: app.globalData.receive_data, //接收的数据
})
},1000)
```
使用定时器实现,可在`onLoad`或者`onShow`函数中加入上述代码(较为合理的位置,当然其它进入页面时触发的函数也都可以)。
## 5、Failed to fetch

遇到上述情况请检查网络连接状态!
# 九、小程序发布
1. 编译之后点击右上角上传按钮进行上传;
2. 弹窗填写版本号和备注点击上传按钮即可;
3. 打开微信公众平台使用之前创建的账号登录,选择左边菜单栏的版本管理;
4. 在版本管理最下面可以看到自己提交的内容,可以点击提交审核,填写如下内容

5. 点击提交审核即可;
6. 提交审核至审核成功前会在审核版本中进行显示,此时若需要开发者之外的用户使用,可将开发版本设为体验版;
7. 审核成功后会在线上版本中显示。
8. 点击设置可以进行小程序码的下载。