微信小程序开发总结

小程序运行环境

运行环境 逻辑层 渲染层
iOS JavaScriptCore WKWebView
安卓 V8 chromium定制内核
小程序开发者工具 NWJS Chrome WebView

需要注意到,小程序运行的三个环境,其底层 执行 JavaScript渲染标记(DOM) 的引擎都不一样。具体那些地方不一样,现在或者将来或许我们都不能仔细去比对,能做的或许就是在实际开发中进行测试。

小程序宿主环境

就像网页开发,js 脚本的宿主环境是浏览器一样,小程序的宿主环境就是微信客户端,因此小程序可以调用微信提供的能力,这类似于微信发布的网页开发工具包 JS-SDK,使得网页开发也能使用微信的能力。

通信模型

小程序有两种线程,一种是 WebView 线程,负责界面的渲染,一种是 JsCore 线程,负责执行 js 脚本。而一个小程序示例会存在多个界面,因此存在多个 WebView 线程。

这两种线程的通信由微信客户端(Native)做中转,逻辑层发送网络请求也经由Native转发,小程序的通信模型下图所示。

程序

小程序通过 app.json 来配置页面:

1
2
3
4
5
6
{
"pages":[
"pages/index/index",
"pages/logs/logs"
]
}

pages 数组中第一个默认为小程序首页。

小程序在微信中初始化完成后调用 onLaunch

1
2
3
4
5
App({
onLaunch: function () {
// 小程序启动之后 触发
}
})

启动小程序过程如图:

小程序只有一个 app 实例,由所以页面共享,因此 app 中的配置同时作用于所有页面,例如:自定义组件,样式等。

页面

小程序由多个页面组成,页面通过构造函数 Page 来注册页面:

1
2
3
4
5
6
7
8
Page({
data: { // 参与页面渲染的数据
logs: []
},
onLoad: function () {
// 页面渲染后 执行
}
})

组件

一个页面由多个组件构成(类似于 html 标签,但是还是统一称作组件),组件的使用于 html 标签使用大体一致。

API

API 提供的就是微信的能力,例如获取用户信息、微信支付等等,API 大多是异步,因此处理异步问题在小程序中很常见。

小程序代码构成

小程序项目文件类型有多达五种:.wxml .wxss .json .js .wxs

  • .wxml 提供结构(html)
  • .wxss 提供样式(css)
  • .json 提供配置
  • .js 提供交互逻辑
  • .wxs js 脚本,可通过 <wxs> 组件引入,类似 <script> 标签

而一个页面或者自定义组件均由以上 5 中文件组成。根据实际情况 .wxss .json .wxs 可不用。

数据驱动

我们知道,网页开发的交互逻辑都是通过 JavaScript 来操作 DOM 来完成;但小程序 JavaScript 脚本运行在 JavaScriptCore(IOS) 或 JsCore(安卓) 中,它们是不包含 BOMDOM 对象的,因此小程序是不能像网页开发一样,直接操作 DOM 节点,这将带来诸多限制。

那我们要如何更新 UI 呢?这就需要理解数据驱动的概念,当前 React Vue 等框架均是采用这种方式来实现 UI 与数据的绑定,通过 JavaScript 来改变数据从而更新 UI

WXML结构实际上等价于一棵Dom树,通过一个JS对象也可以来表达Dom树的结构,如图:

WXML可以先转成JS对象,然后再渲染出真正的Dom树,回到“Hello World”那个例子,我们可以看到转换的过程如图:

这时,如果 JavaScript 将 WXML 的 JS 对象改变了,则:

这就是数据驱动UI,因此,小程序的界面渲染如图:

数据传递

页面与页面的数据传递

  • app 实例
    通过 getApp() 全局接口,可以在小程序初始化后任何地方获取小程序实例的引用。通过操作 app 实例的属性做到页面与页面之间的数据共享。

适合一些不需要缓存的,一次性的状态数据。

  • 本地缓存
    通过 wx.setStorage/wx.getStroage 来操作需要缓存的数据,实现页面与页面之间的数据共享。

  • 服务器存储
    通过调用后端接口来实现对用户配置或状态的数据进行存储,实现页面与页面之间的数据共享。

适合同一用户跨平台、跨终端的数据共享

页面与组件

通过 setData 和 模版数据绑定(数据驱动概念)来实现数据传递

组件与组件

  • 父组件 -> 子组件:属性
  • 子组件 -> 父组件:事件

允许传递的数据类型

因为小程序使用了模版,限于 JSON 字符串化规则,数据中不能包含 function symbol 以及循环引用。

TIP: 通过抽象节点节点的方式,可像自定义组件中传递一个组件。

与 React 的差异

个人决定小程序与React本质上都是已组件化的思想来组织代码,从而构建易维护、可重用的代码;都采用了 diff 算法来优化 DOM 渲染性能。但因小程序使用模版引擎,React使用JSX语法,

  • 小程序组件通信上有组多限制,例如:无法传递函数,无法直接传递组件,没有高阶组件,模版中循环,if 判断不如 js 优雅等。但模版引擎的有点在于可以通过一些特定的指令(例如: bind:tap catch:tap capture-bind:tap)可帮助开发人员快速开发。
  • React 通过JSX,DOM 结构直接表示为 JS 对象,因此 React 能够利用js语言的各种能力,几乎没有限制。但没有限制带来了强大能力的同时也带来了开发者架构负担。

小程序开发过程中遇到的问题

  • 社区生态目前还太弱小,基本都要自己造轮子

  • 小程序是否分包需要在一开始构建目录时就确定好,因为分包不是按配置,而是按目录,不智能

  • 小程序是双线程工作,因此需要处理异步问题,但其本身虽然支持了 es6 语法,但不能成功编译成 es5,例如: async wait。需要自己解决

  • 小程序使用了一部分原生组件,但当原生组件与非原生组件都绑定事件时,从原生组件冒泡到非原生组件在真机上的路径不确定,每次不一致

  • 小程序事件通过DOM传递的数据存在大小写问题(如果命名包含了大写,事件对象中都是小写)

  • 小程序文件上传其实是图片上传,参数 Header 配置的 content-type ,是无法成为后端接口请求的 content-type,实际上,后端接口的 header 可能是微信固定配置的 ‘image/jpg’

  • getMenuButtonBoundingClientRect偶尔获取不到值 。目前可以加延迟 100ms 或者 发现拿到异常值再重新获取