微信小程序入门指南
一、起步
1. 申请账号 链接
点击链接根据指引填写信息和提交相应的资料,就可以拥有自己的小程序帐号。
2. 安装开发工具 链接
前往 开发者工具下载页面 ,根据自己的操作系统下载对应的安装包进行安装。
3. 开发工具预览、远程调试
两种真机调试的方案,各有不同的适用场景和注意事项:
- 预览
- 需要拥有开发者权限的微信账号扫描才能使用,常用于他人在未发版情况下体验最新代码
- 只有IDE登录微信账号扫描时,才和IDE共用一套缓存(此时IDE清缓存可以影响到真机)
- 可以开启调试模式(微信右上角菜单 -> 打开调试),通过 vConsole 按钮展示真机调试区
- 看不到请求具体信息,只能通过控制台打印
- 远程调试
- 可以在PC上看到真机的控制窗口,常用于配合测试人员复现问题
- 独立于IDE缓存,即账号A登录成功远程调试后,账号B进入远程调试,看到的是账号A的信息
- 此时清缓存不能使用IDE清缓存,只能在远程调试窗口执行 wx.clearStore() 这种方式
- 也没有 network
4. 开发工具清缓存
开发和测试中需要经常模拟登录、授权的不同处理结果,此时就需要用到清缓存功能。IDE 提供了以下功能,可以一次全清也可以清除某一项,对应真机调试的实现如下:
- 清除代码缓存
- 相当于真机调试时 - 删除小程序重新加载代码
- 清除授权缓存
- 相当于真机调试时 - 微信右上角菜单 -> 关于xxx -> 右上角菜单 -> 设置
- 清除数据缓存
- 相当于真机调试时 - vConsole -> Wechat -> 点击wx.clearStorage()
- 清除网络缓存
- 真机调试的网络缓存暂不清楚如何清除,静态资源通过增加时间戳
- 注意同一个时间戳对应同一份资源缓存
- Date.parse(new Date()).toString().slice(0, 8) 固定间隔 100s
- Date.parse(new Date()) / (space * 60 * 1000) 根据 space 设置间隔分
- 真机调试的网络缓存暂不清楚如何清除,静态资源通过增加时间戳
- 清除登录缓存
- 由于是静默登录,一般忽视该缓存
5. 开发工具上传
开发完成后,小程序发布前,需要将代码上传到微信的服务器。关于上传有以下需要注意:
- 每个拥有开发权限的账号都可以上传,每个账号上传的代码是分开的
- 每个人只能保持一份上传的代码,二次上传会进行覆盖
- 微信公众平台 / 开发管理
- 线上版本
- 审核版本
- 展示审核中和审核通过但未发布的版本
- 同时只有一个版本进行展示
- 首次审核周期较长,需要3-5个工作日,此后审核较快
- 首次审核较为严格,需要注意很多问题,如诱导分享,详见常见拒绝情形
- 开发版本
- 每个版本都可以设为体验版本,但同时只有一个体验版本,通过二维码供拥有体验者权限的人进行测试
- 每个版本都可以提交审核,但同时只有一个审核中版本
- 每个账号维护一份开发版本
7. 开发工具详情(IDE右上角)
- 项目设置
- 可以选择调试基础库,来测试兼容问题(存在兼容问题的 api 都写了最低版本,也可以查看 历史更新日志 进行了解)
- 未设置合法域名时,可以勾选 不校验安全域名 选项(线上域名一定要 TLS/SSL 认证)
- 域名信息
- 查看合法域名
8. 代码构成
1. JSON 配置 2. WXML 模版 3. WXSS 样式 4. JS逻辑交互
二、开发优化
1. promisify
由于小程序提供的 API 都是回调风格的,在习惯了 ES6 promise 风格后,对回调嵌套不是很感冒,所以考虑进行包装处理。此处小程序提供的 Promise 有兼容问题,所以使用了 es6-promise 包来进行包装。
/** * 将小程序的API封装成支持Promise的API * @params fn {Function} 小程序原始API,如wx.login */ function wxPromisify(fn) { return (obj = {}, cb) => { return new Promise((resolve, reject) => { obj.success = (res) => { resolve(res); }; obj.fail = (res) => { reject(res); }; let taskObj = fn(obj); cb && (typeof cb == 'function') && cb(taskObj); }) } }
2. request
小程序提供的原生接口是 wx.request ,出于以下几点考虑,对其进行二次封装:
- 小程序没有 cookie ,需要在 heaser 中携带 sessionId
- 原生写法是回调风格,改造成 promise 风格
- 需要公用部分业务相关的数据处理
- 需要对请求进行统一拦截处理,如 loading 、timeout
3. 按钮节流阀
经常这种需求,按钮不能连续点击,所以提供一个节流功能的工具:
function btnThrottle(self){ selt.setData({ buttonClicked: true }); setTimeout(() => { self.setData({ buttonClicked: false }) }, 500) } creat: function() { if(this.data.buttonClicked) return; util.btnThrottle(this); }
4. 代码清缓存
有时候在调试的时候需要经常保持代码最新,经常执行删除小程序还是很麻烦的,可以考虑使用下面方法:
onHide: function() { wx.setEnableDebug({ enableDebug: true, success: () => { wx.setEnableDebug({ enableDebug: false }) } }) }
- 优点:可以清除代码缓存,每次打开都是重新加载
- 缺点:没办法保持退出时的状态,所以暂不考虑用到生产环境
三、常见问题
1. 登录逻辑
官方建议自己保存用户登录状态,不要频繁调用 wx.login ,否则会被限制登录。
有两种思路:
- 先检查登录是否过期(wx.checSsession),在未过期的基础上执行其他请求
- 所有 api 请求都执行判断,如果返回未登录错误码(getUserInfo:fail auth deny),则申请授权(wx.authorize),授权成功继续请求,授权拒绝则强跳授权页(wx.openSetting)
目前登录判断:
- wx.checkSession、wx.getStorage 检查登录是否过期和 sessionId 是否存在
- 成功则判断结束,否则 wx.login、wx.getUserInfo 拿到用户信息
- 成功则用拿到的信息向后台登录生成 sessionId,失败则申请授权操作(允许授权会继续,失败授权强跳授权页)
- 成功拿到 sessionId 则保存 storage,失败提示网络问题
- 调用 wx.login 获取 code,然后从微信后端换取到 session_key,用于解密 getUserInfo返回的敏感数据。
- 使用 wx.getSetting 获取用户的授权情况
- 如果用户已经授权,直接调用 API wx.getUserInfo 获取用户最新的信息;
- 用户未授权,在界面中显示一个按钮提示用户登入,当用户点击并授权后就获取到用户的最新信息。
- 获取到用户数据后可以进行展示或者发送给自己的后端
2. 路由跳转相关
系统 api 和 navigator 组件支持新开、重定向、返回、tab切换、重启动五种方式。读懂路由出入栈规则,可以帮你较好的处理跳转问题。但归根结底我们还是应该避免过于复杂的跳转逻辑,防止分享进入时的路由跳转问题。
有一种情况需要格外注意,在实现后退功能的时候,可能已经没有办法后退了(如分享卡片进入或已经退出当前页面但代码还在执行),此时执行 wx.navigateBack 会闪退。
// 兼容处理不同打开方式的后退 function toHome() { let pageCount = getCurrentPages().length; if(pageCount > 1) { wx.navigateBack({ delta: 1 }) } else { wx.redirectTo({ url: '/pages/home/index' }) } }
需要注意的是 tab 切换时的路由出入栈规则:
- tab a 到 tab b 相互切换时,触发的是 onHide 和 onShow(第一次切换会有 onLoad)
- tab a 的子页面切到 tab b 时,会把所有 a 的子页面 onUnload
3. 数据共享的实现
- url传值 - 基于页面 - 适合少量值传递
wx.navigateTo({ url: '/page/home/index?id=' + id }) onload: function(opt) { console.log(opt.query) }
- storage - 基于本地缓存 - 适合大量值传递
注:
- 同一个微信用户,同一个小程序 storage 上限为 10MB
- localStorage 以用户维度隔离,同一台设备上,A 用户无法读取到 B 用户的数据
- 不建议将关键信息全部存在 localStorage,以防用户换设备的情况
- 全局 App - 基于内存
getApp().globalData.xxx
4. 退出当前页面后,代码还在执行
由于用户退出页面的操作具有不可控性,所以随时都可能出现代码不在当前页面执行的情况,而这种情况并不是我们想要看到的。所以需要对这种情况进行处理,保证代码执行稳定可控。常见的有异步请求、定时器。所以最基本的要求就是在退出页面是执行以下操作:
onUnload: function () { // 中断请求 if (wx.canIUse('requestTask.abort')) { this.abortInit && this.abortInit.abort(); } // 清理定时器 clearInterval(this.xxxTimer); // 重置数据 self.setData({ //... }); },
但总有漏网之鱼,在开发中我就遇到过,请求中断了,定时器清理了以后还在执行的情况。出现这种情况第一感觉并没有清理成功,API 执行出现了问题。
后来测试多次发现,并非 API 的锅,而是因为在未能中断的异步操作中触发了新的异步操作,而新的异步操作已经无法控制中断。 如:某个 request 请求没能 abort 中断,该操作的回调中又调起了另一个 request 或 setTimeout ,此时场面失控了。
所以,流程清晰可控是必须的,各位在处理业务逻辑的时候一定要注意此类问题的出现。
5. share
作为非常重要的一个推广途径,用户分享自然是个很重要的功能点,小程序提供了相关的 API ,在使用中遇到以下问题并记录:
- 分享最终执行的是 onShareAppMessage 对应的函数,相关的逻辑在其中处理
- 分享的参数 imageUrl 存在低版本兼容问题,设置为 null 不能实现默认截屏, '' 可以截屏
- 分享可以携带参数,写在 path 参数中即可,同 url 中的 query
- 如果需要获取该参数,可以在 onShow 的参数 options 中获取到
- 场景需要:分享到群判断,并判断是否群分享进入
- 先设置带 shareTicket 的转发
wx.showShareMenu({ withShareTicket: true });
- 在分享的成功回调函数中判断 shareTickets 群标识,存在即为分享到群
- 获取场景值(onShow 的参数 options 中 scene),判断进入方式,常用场景值:
- 1007:单人对话小程序卡片
- 1036:App 分享消息卡片
- 1044:群分享小程序卡片
6. 自定义分析
产品的良性发展自然少不了运营进行数据分析,常规做法是进行埋点统计。而小程序已经提供给用户一套相对来说比较完善的数据分析功能,可以登录微信公众平台 -> 数据分析查看,也可以通过小程序助手(官方小程序)便捷查看,当前前提是需要账号拥有数据分析的权限。
虽然官方提供的数据分析已经满足大部分需求,但是实际生产中肯定还需要定制数据分析,这里也有提供自定义分析。实现起来就是,先在微信公众平台进行自定义分析的事件注册,如果选择 API 上报则还是需要进行埋点配合。以下对自定义分析作简要说明:
- 最低版本
- 自定义数据上报仅对微信6.5.4及以上版本生效,涉及时间为 2017-01-23 以后更新即可
- 新建事件
- 事件名称
- 英文名称:用于 API 上报
- 中文名称:用户管理后台
- 配置信息
- 动作触发
- trigger
- click
- 生命周期
- share
- switchTab
- action
- 一次性
- 分步骤
- page
- app 层面的不用设置,默认 ANY_PAGE
- element
- click 需要触发元素,类或id选择器
- data
- 收集数据源,有默认字段和自定义字段
- 自定义字段
- 默认是从 page 实例的 data 中获取,字段名用于统计显示,字段值是指 data 中的 key
- 也可以选择其他数据,看文档(渲染出来的list 、 wxml中的data-、 app实例的数据、系统属性)
- trigger
- API上报
- 字段信息可以不填
- 可自动生成代码
- 二者的选择
- 根据实际情况来,有时候点击满足不了要求
- 动作触发
- 测试事件
- 保存并测试
- 连续测试有时候测不到数据,不要担心,退出公众平台账号重新登录再测
- 发布事件
- 保存并发布
7. 微信服务通知
场景需求:开发者希望主动发送信息给用户
说明:该功能不建议频繁发送信息,可能会被用户主动拒收,而且该功能需要用户本人在微信体系内与页面有交互行为后触发(主动触发)
重点:获取用户的 formid
实现:
- 必须通过 form 组件提交才能获取 formid
- form 组件设置 report-submit='true'
- form 组件添加 bindsubmit 事件, event.detail = {value: {'name': 'value'}, formId: ''}
- 必须用户手动触发提交表单,不能 js 模拟提交,即必须有按钮
8. 小程序互相跳转
- 基础库 1.3.0 开始支持,低版本需做兼容处理
- iOS 微信客户端 6.5.9 版本开始支持,Android 客户端即将在 6.5.10 版本开始支持,请先使用 iOS 客户端进行调试
注:需要关联同一公众号
写在最后
以上内容并不能帮助大家熟练完成小程序开发,只是简单入门、踩坑记录、常见业务场景处理,还有非常多自己还没踩到的东西,如自定义组件、插件、分包加载都还没使用,API 也只用了有限的几个,比较重要的 微信支付 也未使用,后面用到了再一一记录。写出来方便大家快速接入小程序,也是自己的学习总结,有描述错误或不完善的地方,还请大家能够和我联系,相互学习交流。