随记支付宝小程序

小程序踩坑之旅

2019-08-19  本文已影响0人  ArmorVon

最近几个月因为公司的业务需求,一直在折腾小程序,从开始的完全不熟悉,到后面被各种坑折磨,是时候写一篇总结了,避免下一次遇到还找不到解决的方案。

目录:

配置项app.json和page.json

app.json

首先,需要确定的是,app.json 是小程序的全局配置,放在根目录下。

常用的一些字段如下:

page.json

页面的样式配置优先级比全局配置中的window高。

sitemap.json文件(用于微信索引)

默认规则为都默认被索引:

{"action": "allow", "page": "*"}

语法区别

wxml文件跟html的区别:

问题思考?

wx:ifhidden该怎么合理的判断使用场景?

组件

基础组件

原生组件的使用限制

事件系统

思考:

  1. 小程序中bind事件和catch事件有什么区别?
  1. target和currentTarget有什么不同?
<view id="outer" bindtap="handleTap1">
  outer view
  <view id="middle" catchtap="handleTap2">
    middle view
    <view id="inner" bindtap="handleTap3">
      inner view
    </view>
  </view>
</view>

如上面这个示例中,点击inner view会触发handleTap3,同时会冒泡到handleTap2。
对于handleTap2这个组件来说,此时收到事件对象的target就是inner的元素,而currentTarget是middle的部分

  1. mark 和 dataset 有什么区别?

小程序相关机制

小程序的运行机制:冷启动和热启动

启动场景

更新机制

ES6的支持情况:

注册小程序

App({
  onLaunch: function(options) {},
  onShow: function(options) {},
  onHide: function() {},
  onError: function(msg) {},
  globalData: 'I am global data'
})

注册页面和自定义组件

页面

Page构造器:

Page({
  data: { text: "This is page data." },
  onLoad: function(options) { },
  onReady: function() { },
  onShow: function() { },
  onHide: function() { },
  onUnload: function() { },
  onPullDownRefresh: function() { },
  onReachBottom: function() { },
  onShareAppMessage: function () { },
  onPageScroll: function() { }
})

自定义组件

// page-common-behavior.js
module.exports = Behavior({
  attached: function() {
    // 页面创建时执行
    console.info('Page loaded!')
  },
  detached: function() {
    // 页面销毁时执行
    console.info('Page unloaded!')
  }
})


// 页面 A
var pageCommonBehavior = require('./page-common-behavior')
Component({
  behaviors: [pageCommonBehavior],
  data: { /* ... */ },
  methods: { /* ... */ },
})


// 页面 B
var pageCommonBehavior = require('./page-common-behavior')
Component({
  behaviors: [pageCommonBehavior],
  data: { /* ... */ },
  methods: { /* ... */ },
})

注意:

组件间的通信与事件

此处列举第二种自定义事件传递数据的方法:

// 1. 父组件中监听事件
<component-tag-name bindmyevent="onMyEvent" />

// 2. 子组件触发事件,触发wxml的onMyEvent事件,触发父组件的方法
<!--自定义组件中-->
<button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>

<!--自定义组件js文件中-->
Component({
  properties: {},
  methods: {
    onTap: function(){
      var myEventDetail = {} // detail对象,提供给事件监听函数
      var myEventOption = {} // 触发事件的选项
      this.triggerEvent('myevent', myEventDetail, myEventOption)
    }
  }
})

具体可参考文档: 组件间通信与事件

注意:

组件间关系

场景: 如果一个页面中需要使用到A组件和B组件,而A组件与B组件之间需要通信,此时可以在组件定义时加入relations定义段,如封装的ul和li组件后,之间需要存在关联的父子关系

具体使用方式参见 组件间关系

使用setData应注意的事项:

小程序运行流程

  1. 微信打开小程序前,会把整个小程序的代码包下载到本地
  2. 通过 app.json 的 pages 字段就可以知道你当前小程序的所有页面路径
  3. 写在 pages 字段的第一个页面就是这个小程序的首页(打开小程序看到的第一个页面),所以微信会把首页的代码装载进来
  4. 小程序启动,触发app.js 定义的 App 实例的 onLaunch回调,启动时也会触发onShow函数,或切前台、从其他页面返回到这个页面,都会触发onShow;onHide监听小程序切后台,(如tab切换,navigateTo,离开微信等); onPageNotFound页面不存在监听函数
  5. 页面的渲染流程开始,微信客户端会先根据 page的json文件配置生成一个界面,
  6. 接着装载这个页面的 WXML 结构和 WXSS 样式
  7. 最后客户端会装载 page的js文件
  8. Page构造器会生成一个页面,生成页面的时候小程序框架会把 data 数据和 index.wxml 一起渲染出最终的结构,渲染完界面
  9. 渲染完界面之后,页面实例就会收到一个 onLoad 的回调

生命周期函数

小程序里面又三种生命周期:小程序运行的生命周期(在app.js中处理),页面的生命周期(在page的js文件中处理,或者组件的pageLifetimes触发的生命周期函数),组件的生命周期

小程序生命周期函数

onLaunch,onShow参数:

页面生命周期函数

组件生命周期函数

注意:

组件中存在一个组件所在页面的生命周期,定义在pageLifetimes中,其中可用的生命周期包括:

网络

  1. 服务器域名配置,当使用体验版或者开发版报“服务器开小差”了的错误,大部分可能性都是因为没有打开调试,因为在调试模式下,小程序不会去校验域名的合法性。
  2. 小程序只可以跟指定的域名与进行网络通信,包括普通 HTTPS 请求(wx.request)、上传文件(wx.uploadFile)、下载文件(wx.downloadFile) 和 WebSocket 通信(wx.connectSocket)
  3. 如果接入第三方网页,使用web-view组件,需要配置业务域名
  4. 默认超时时间为60s,超时时间可以在 app.json 或 game.json 中通过 networktimeout 配置
  5. 并发限制:wx.request、wx.uploadFile、wx.downloadFile 的最大并发限制是 10 个;wx.connectSockt 的最大并发限制是 5 个
  6. 返回状态,只要成功接收到服务器返回,无论 statusCode 是多少,都会进入 success 回调

自定义tabBar

用户可以通过配置app.json 中的 tabBar 项指定 custom 字段为true,来自定义tabBar,不过有些使用地方还需要注意:

  1. tabBar 的相关配置项仍然需完整声明,以兼容低版本以及区分哪些是tab页
  2. 需要用户自定义一个组件来渲染 tabBar,推荐用 fixed 在底部的 cover-view + cover-image 组件渲染样式,以保证 tabBar 层级相对较高
  3. 与 tabBar 样式相关的接口,如 wx.setTabBarItem 等将失效
  4. 可以在自定义组件下通过 getTabBar 接口,获取当前页面的自定义 tabBar 组件实例

小程序登录流程

小程序登录需要调用微信的开放接口,整体流程如下:

  1. 小程序通过wx.login()获取一个code
  2. 调用后端的api,发送code,后端通过这个code来校验接口,并返回一个自定义登录态
  3. 小程序将登录状态存入storage
  4. 之后再访问服务器发送业务请求就只用后端判断登录态查询openid和session_key返回业务数据

小程序优化操作

  1. 缩短白屏时间:
    • 首屏渲染的内容较多,需要集合多份数据进行渲染:此时可以把优先级高的内容做优先展示
    • 首屏内容依赖的数据从服务端请求的时间太长:分析数据返回的时间长的原因
    • 一次性渲染数据太大或依赖的计算过于复杂:减少渲染的数据量、优化渲染相关数据的算法
  2. 渲染界面的耗时过长,需要校验下是否同时渲染的区域太大(例如列表过长)
  3. 脚本执行时间过长:需要确认并优化脚本的逻辑
  4. setData调用频繁:避免无用的频繁调用,每秒调用setData的次数不超过 20 次,
// 不要频繁调用setData
    this.setData({ a: 1 })
    this.setData({ b: 2 })
// 绝大多数时候可优化为
    this.setData({ a: 1, b: 2 })
  1. setData的数据太大,setData的数据在JSON.stringify后不超过 256KB
  2. setData一个未绑定的变量
// 不要设置不在界面渲染时使用的数据,并将界面无关的数据放在data外
    this.setData({
      myData: {
        a: '这个字符串在WXML中用到了',
        b: '这个字符串未在WXML中用到,而且它很长…………………………'
      }
    })
    // 可以优化为
    this.setData({
      'myData.a': '这个字符串在WXML中用到了'
    })
    this._myData = {
      b: '这个字符串未在WXML中用到,而且它很长…………………………'
    }

  1. 开启 HTTP 缓存控制
  2. 控制WXML节点数
<view data-my-data="{{myData}}"> <!-- 这个 view 和下一行的 view 可以合并 -->
  <view class="my-class" data-my-data="{{myData}}" bindtap="onTap">
    <text> <!-- 这个 text 通常是没必要的 -->
      {{myText}}
    </text>
  </view>
</view>

<!-- 可以简化为 -->

<view class="my-class" data-my-data="{{myData}}" bindtap="onTap">
  {{myText}}
</view>
  1. 控制图片大小,图片宽高都不超过实际显示宽高的3倍
  2. 合理控制网络请求数量
  3. 控制图片请求数
  4. 开启惯性滚动:wxss中带有overflow: scroll的元素,在 iOS 下需要设置-webkit-overflow-scrolling: touch样式
  5. 避免使用:active伪类来实现点击态
  6. 保持图片大小比例
  7. 可点击元素的宽高都不小于 20px
  8. iphoneX兼容,用以下wxss进行兼容:
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
  1. 避免JS异常
  2. 不使用废弃接口
  3. 设置最低基础库版本
  4. 移除不可访问到的页面
  5. 移除大量未使用的样式
  6. 及时回收定时器:定时器是全局的,并不是跟页面绑定的,当小程序从一个页面路由到另一个页面之后,前一个页面定时器应注意手动回收
上一篇 下一篇

猜你喜欢

热点阅读