小程序的运行环境差异
小程序开发流程
注册小程序:申请帐号
注册小程序链接:https://mp.weixin.qq.com/wxopen/waregister?action=step1
登录小程序后台
登录链接:https://mp.weixin.qq.com/
在菜单 “开发”-“开发设置” 看到小程序的 AppID
开发工具下载
微信开发者工具下载链接:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html
新建小程序:如下图步骤
注:没有APPID会限制功能体验具体参照微信开发者文档!
小程序文件的相关作用
-
.json
后缀的JSON
配置文件 -
.wxml
后缀的WXML
模板文件 -
.wxss
后缀的WXSS
样式文件 -
.js
后缀的JS
脚本逻辑文件 -
app.json
是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等
小程序全局配置文档(app.json文件):https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
小程序页面配置文档(每个页面的json文件)https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/page.html
页面中配置项在当前页面会覆盖 app.json
的 window
中相同的配置项
sitemap 配置文档:https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/sitemap.html
开发者可以通过 sitemap.json
配置,或者管理后台页面收录开关来配置其小程序页面是否允许微信索引。当开发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户的搜索词条触发该索引时,小程序的页面将可能展示在搜索结果中
项目配置文件(project.config.json)文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html
配合weui使用
组件库文档:https://developers.weixin.qq.com/miniprogram/dev/extended/weui/
在全局配置app.json文件下增加如下配置即可正常使用内部组件
"useExtendedLib": { "weui": true },
"usingComponents": { "mp-icon": "weui-miniprogram/icon/icon" }
小程序测试号申请
微信扫描二维码,即可获得为自己分配好的小程序和小游戏测试账号
链接:https://mp.weixin.qq.com/wxamp/sandbox?doc=1
发布上线
一个小程序从开发完到上线一般要经过 预览-> 上传代码 -> 提交审核 -> 发布等步骤
代码管理(也可上传自己的git)
运营数据查看
有两种方式可以方便的看到小程序的
方法一:登录
方法二:使用小程序数据助手,在微信中方便的查看运营数据
小程序开发注意事项
允许上传的文件
只有后缀名在白名单内的文件可以被上传,不在白名单列表内文件在开发工具能被访问到,但无法被上传
-
wxs
-
png
-
jpg
-
jpeg
-
gif
-
svg
-
json
-
cer
-
mp3
-
aac
-
m4a
-
mp4
-
wav
-
ogg
-
silk
-
wasm
-
br
小程序生命周期
App() 必须在 app.js
中调用,必须调用且只能调用一次。不然会出现无法预期的后果
页面路由
-
-
switchTab
只能打开 tabBar 页面。 -
reLaunch
可以打开任意页面。 -
页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
-
调用页面路由带的参数可以在目标页面的
onLoad
基础库
ES6 转 ES5
在 0.10.101000 以及之后版本的开发工具中,会默认使用 babel
将开发者 ES6
语法代码转换为三端都能很好支持的 ES5
的代码,帮助开发者解决环境不同所带来的开发问题
小程序检测版本更新(启动时更新和未启动时更新)
未启动时更新
开发者在管理后台发布新版本的小程序之后,如果某个用户本地有小程序的历史版本,此时打开的可能还是旧版本。微信客户端会有若干个时机去检查本地缓存的小程序有没有更新版本,如果有则会静默更新到新版本。总的来说,开发者在后台发布新版本之后,无法立刻影响到所有现网用户,但最差情况下,也在发布之后 24 小时之内下发新版本信息到用户。用户下次打开时会先更新最新版本再打开
启动时更新
在app.js中载入
onShow() { //使用更新对象之前判断是否可用 if (wx.canIUse(\'getUpdateManager\')) { const updateManager = wx.getUpdateManager() updateManager.onCheckForUpdate(function (res) { // 请求完新版本信息的回调 console.log(res.hasUpdate) // res.hasUpdate返回boolean类型 if (res.hasUpdate) { updateManager.onUpdateReady(function () { wx.showModal({ title: \'更新提示\', content: \'新版本已经准备好,是否重启当前应用?\', success(res) { if (res.confirm) { // 新的版本已经下载好,调用applyUpdate应用新版本并重启 updateManager.applyUpdate() } } }) }) // 新版本下载失败时执行 updateManager.onUpdateFailed(function () { wx.showModal({ title: \'发现新版本\', content: \'请删除当前小程序,重新搜索打开...\', }) }) } }) } else { //如果小程序需要在最新的微信版本体验,如下提示 wx.showModal({ title: \'更新提示\', content: \'当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。\' }) } },
封装一个方法也行onLaunch()钩子中调用
checkUpdateVersion() { //判断微信版本是否 兼容小程序更新机制API的使用 if (wx.canIUse(\'getUpdateManager\')) { //创建 UpdateManager 实例 const updateManager = wx.getUpdateManager(); console.log(\'是否进入模拟更新\'); //检测版本更新 updateManager.onCheckForUpdate(function (res) { console.log(\'是否获取版本\',res); // 请求完新版本信息的回调 if (res.hasUpdate) { //监听小程序有版本更新事件 updateManager.onUpdateReady(function () { //TODO 新的版本已经下载好,调用 applyUpdate 应用新版本并重启 ( 此处进行了自动更新操作) updateManager.applyUpdate(); }) updateManager.onUpdateFailed(function () { // 新版本下载失败 wx.showModal({ title: \'已经有新版本喽~\', content: \'当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试!\', }) }) } }) } else { //TODO 此时微信版本太低(一般而言版本都是支持的) wx.showModal({ title: \'更新提示\', content: \'当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试!\' }) } },
低版本兼容处理
if (wx.openBluetoothAdapter) { wx.openBluetoothAdapter() } else { // 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示 wx.showModal({ title: \'提示\', content: \'当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。\' }) }
对于 API 的参数或者返回值有新增的参数,可以判断用以下代码判断
wx.showModal({ success: function(res) { if (wx.canIUse(\'showModal.success.cancel\')) { console.log(res.cancel) } } })
组件兼容处理使用组件的地方判断是否可支持使用
data: { canIUse: wx.canIUse(\'cover-view\') }
设置最低基础库版本:登录小程序管理后台,进入「设置 - 基本设置 - 基础库最低版本设置」进行配置
小程序授权登录
-
-
调用
-
服务器域名请在 「小程序后台-开发-开发设置-服务器域名」 中进行配置,配置时需要注意:
-
域名只支持
https
( -
域名不能使用 IP 地址(小程序的
-
可以配置端口,如 https://myserver.com:8080,但是配置后只能向 https://myserver.com:8080 发起请求。如果向 https://myserver.com、https://myserver.com:9091 等 URL 请求则会失败。
-
如果不配置端口。如 https://myserver.com,那么请求的 URL 中也不能包含端口,甚至是默认的 443 端口也不可以。如果向 https://myserver.com:443 请求则会失败。
-
域名必须经过 ICP 备案;
-
出于安全考虑,
api.weixin.qq.com
不能被配置为服务器域名,相关API也不能在小程序内调用。 开发者应将 AppSecret 保存到后台服务器中,通过服务器使用getAccessToken
接口获取access_token
,并调用相关 API; -
不支持配置父域名,使用子域名
开发者代码注入优化
自基础库版本 2.11.1 起,小程序支持
{ "lazyCodeLoading": "requiredComponents" }
添加这项配置后,未使用到的代码文件将不被执行
其他优化
-
-
-
骨架屏
-
缓存请求数据
-
精简首屏数据:推荐开发者延迟请求非关键渲染数据,与视图层渲染无关的数据尽量不要放在 data 中,加快页面渲染完成时间
-
性能数据获取:
-
性能得分:
-
首屏时间不超过 5 秒
-
渲染时间不超过 500ms
-
一个执行周期内脚本运行时间不超过 1 秒
-
每秒调用
setData
的次数不超过 20 次 -
setData
的数据在JSON.stringify
后不超过 256KB -
页面WXML节点少于 1000 个,节点树深度少于 30 层,子节点数不大于 60 个
-
所有图片均开启 HTTP 缓存
-
图片宽高乘积 <= 实际显示宽高乘积 * (设备像素比 ^ 2)
-
所有网络请求都在 1 秒内返回结果
-
通过
wx.request
发起的耗时超过 300ms 的请求并发数不超过 10 个 -
同域名耗时超过 100ms 的图片请求并发数不超过 6 个
-
3 分钟以内同一个url请求不出现两次回包大于 128KB 且一模一样的内容
-
小程序基础语法
数据绑定
<view> {{ message }} </view>
<view id="item-{{id}}"> </view>
<checkbox checked="{{false}}"> </checkbox>
三元运算
<view hidden="{{flag ? true : false}}"> Hidden </view>
算术运算
<view> {{a + b}} + {{c}} + d </view>
遍历
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName"> {{idx}}: {{itemName.message}} </view>
条件渲染(wx:if
有更高的切换消耗而 hidden
<view wx:if="{{condition}}"> </view>
使用 name 属性,作为模板的名字。然后在<template/>
内定义代码片段
<template name="msgItem"> <view> <text> {{index}}: {{msg}} </text> <text> Time: {{time}} </text> </view> </template>
使用模板:用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入;
<template is="msgItem" data="{{...item}}"/>
引用:WXML 提供两种文件引用方式import
和include
<import src="item.wxml"/>
<include src="header.wxml"/>
import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件 import 的 template
include
tabbar的配置(小程序自带配置好页面和路径以及图标和选中图标即可生效)
"tabBar": { "color": "#6e6d6b", "selectedColor": "#f9f027", "borderStyle": "white", "backgroundColor": "#000", "list": [ { "pagePath": "pages/index/index", "iconPath": "images/tabbar-01.png", "selectedIconPath": "images/tabbar-01-active.png", "text": "首页" }, { "pagePath": "pages/sort/index", "iconPath": "images/tabbar-02.png", "selectedIconPath": "images/tabbar-02-active.png", "text": "分类" }, { "pagePath": "pages/cart/index", "iconPath": "images/tabbar-03.png", "selectedIconPath": "images/tabbar-03-active.png", "text": "购物车" }, { "pagePath": "pages/my/index", "iconPath": "images/tabbar-04.png", "selectedIconPath": "images/tabbar-04-active.png", "text": "我的" } ] },
常用API
一般建议该用同步的时候就要用同步,同步解决不了的问题再用异步
wx.canIUse(string schema)
判断小程序的API,回调,参数,组件等是否在当前版本可用
wx.getSystemInfo() 系统信息(同步版本)
wx.getSystemInfoAsync() 系统信息(异步版本)
wx.getSystemInfo() 获取系统信息[一般用这个就好]
try { const res = wx.getSystemInfoSync() console.log(res) } catch (e) { // Do something when catch error }
wx.getSystemInfo({
success (res) {
console.log(res)
}
})
wx.updateWeChatApp(Object object)
wx.updateWeChatApp({ success(res){ console.log(res,\'res\') } })
wx.getUpdateManager()
获取全局唯一的版本更新管理器,用于管理小程序更新(相关代码前面小程序检测版本更新章节有参考)
关于小程序页面跳转
wx.switchTab()
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
wx.reLaunch()
关闭所有页面,打开到应用内的某个页面
wx.redirectTo()
关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
wx.navigateTo()
保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层
wx.navigateBack()
关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层
wx.switchTab({ url: \'/index\' }) wx.reLaunch({ url: \'test?id=1\' }) // 页面内获取参数 Page({ onLoad (option) { console.log(option.query) } }) wx.redirectTo({ url: \'test?id=1\' }) wx.navigateTo({ url: \'test?id=1\' }) wx.navigateBack({ delta: 2 })
wx.showLoading(Object object)
wx.showToast(Object object)
wx.showToast({ title: \'操作成功\', icon: \'loading\', // success(成功) | error(失败) | loading(加载中..) | none(无图标) duration: 2000, })
wx.showModal({ title: \'提示\', content: \'这是一个模态弹窗\', success (res) { if (res.confirm) { console.log(\'用户点击确定\') } else if (res.cancel) { console.log(\'用户点击取消\') } } })
wx.setNavigationBarTitle({ title:\'自定义标题覆盖当前设置的\' })
wx.setNavigationBarColor() 设置页面导航条颜色 背景字体样式对应api也可设置
wx.setNavigationBarColor({ frontColor: \'#ffffff\', backgroundColor: \'#ff0000\', animation: { duration: 400, timingFunc: \'easeIn\' } })
wx.hideHomeButton() 隐藏返回首页按钮
微信7.0.7版本起,当用户打开的小程序最底层页面是非首页时,默认展示“返回首页”按钮,开发者可在页面 onShow 中调用 hideHomeButton 进行隐藏。
wx.showTabBar() 显示 tabBar
wx.hideTabBar() 隐藏 tabBar
wx.pageScrollTo(Object object)
将页面滚动到目标位置,支持选择器和滚动距离两种方式定位
wx.pageScrollTo({ scrollTop: 0, duration: 300 })
wx.request(Object object) 网络请求(ajax)
wx.request({ url: \'/api/login\', //仅为示例,并非真实的接口地址 data: { parmas1: \'\', parmas2: \'\' }, header: { \'content-type\': \'application/json\' // 默认值 }, success (res) { console.log(res.data) } })
wx.uploadFile() 上传文件
wx.chooseImage({ success (res) { const tempFilePaths = res.tempFilePaths wx.uploadFile({ url: \'https://example.weixin.qq.com/upload\', //仅为示例,非真实的接口地址 filePath: tempFilePaths[0], name: \'file\', formData: { \'user\': \'test\' }, success (res){ const data = res.data //do something } }) } })
wx.downloadFile({ url: \'https://example.com/audio/123\', //仅为示例,并非真实的资源 success (res) { // 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容 if (res.statusCode === 200) { wx.playVoice({ filePath: res.tempFilePath }) } } })
小程序数据缓存
wx.setStorageSync() 将数据存储在本地缓存中指定的key中(同步)
wx.setStorage() 从本地缓存中移除指定 key(异步)
wx.removeStorageSync() 从本地缓存中移除指定 key[同步]
wx.removeStorage() 从本地缓存中移除指定 key[异步]
wx.getStorageSync() 从本地缓存中获取指定 key[同步]
wx.getStorage() 从本地缓存中获取指定 key[异步]
wx.clearStorageSync() 清除缓存所有key[同步]
wx.clearStorage() 清除缓存所有key[异步]
wx.getStorageInfoSync() 从本地缓存中获取所有 key(同步)
wx.getStorageInfo() 从本地缓存中获取所有 key(异步)
最后面两个几乎用不上
// 设置 try { wx.setStorageSync(\'key\', \'value\') } catch (e) { } // 移除 try { wx.removeStorageSync(\'key\') } catch (e) { // Do something when catch error } // 获取 try { var value = wx.getStorageSync(\'key\') if (value) { // Do something with return value } } catch (e) { // Do something when catch error } // 清除 try { wx.clearStorageSync() } catch(e) { // Do something when catch error }
wx.getLocation() 获取当前的地理位置、速度。 开启高精度定位,接口耗时会增加,可指定 highAccuracyExpireTime 作为超时时间。地图相关使用的坐标格式应为 gcj02。
使用:在app.json文件中配置
"permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序位置接口的效果展示" } }
wx.getLocation({ type: \'wgs84\', success (res) { console.log(res,\'res\') } })
wx.getLocation({ type: \'gcj02\', //返回可以用于wx.openLocation的经纬度 success (res) { const latitude = res.latitude const longitude = res.longitude // 使用微信内置地图查看位置 wx.openLocation({ latitude, longitude, scale: 18 // 5 - 18 级 缩放比例 }) } })
wx.chooseLocation() 打开地图选择位置
wx.showShareMenu() 显示当前页面的转发按钮参数
-
"shareAppMessage"表示“发送给朋友”按钮,"shareTimeline"表示“分享到朋友圈”按钮
-
wx.showShareMenu({ withShareTicket: true, menus: [\'shareAppMessage\', \'shareTimeline\'] })
// 隐藏当前页面的转发按钮 wx.hideShareMenu({ menus: [\'shareAppMessage\', \'shareTimeline\'] })
wx.showShareImageMenu() 打开分享图片弹窗
wx.showShareImageMenu({ path: \'../../images/tabbar-01-active.png\', })
wx.shareVideoMessage() 转发视频到聊天(功能类似分享图片)
wx.shareFileMessage() 转发文件到聊天(功能类似分享图片)
wx.scanCode() 调起客户端扫码界面进行扫码
// 允许从相机和相册扫码 wx.scanCode({ success (res) { console.log(res) } })
wx.authorize() 授权
调用后会立刻弹窗询问用户是否同意授权小程序使用某项功能或获取用户的某些数据,但不会实际调用对应接口。如果用户之前已经同意授权,则不会出现弹窗,直接返回成功。
小程序插件可以使用
// 可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.record" 这个 scope wx.getSetting({ success(res) { if (!res.authSetting[\'scope.record\']) { wx.authorize({ scope: \'scope.record\', success () { // 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问 wx.startRecord() } }) } } })
授权列表
授权有效期
一旦用户明确同意或拒绝过授权,其授权关系会记录在后台,直到用户主动删除小程序。
最佳实践
在真正需要使用授权接口时,才向用户发起授权申请,并在授权申请中说明清楚要使用该功能的理由。
注意事项
-
wx.authorize({scope: "scope.userInfo"})
,不会弹出授权窗口,请使用 <button open-type="getUserInfo"/> -
请发表评论