多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
小程序可以调用宿主环境提供的微信客户端的能力,这就使得小程序比普通网页拥有更多的能力,组合这些能力可以完成一个体验非常流畅的小程序。 小程序会运行在不同版本的宿主环境下,因此针对各个版本的宿主环境做程序上的兼容也是在所难免的,以便给不同环境下的的微信用户提供可靠或者降级的服务。 [【官方文档】](https://developers.weixin.qq.com/ebook?action=get_post_info&token=935589521&volumn=1&lang=zh_CN&book=miniprogram&docid=0004a2ef9b8f803b0086831c75140a) [TOC] ## 小程序的启动 1. **下载小程序代码包**。微信客户端在打开小程序之前,会把整个小程序的代码包下载到本地。 2. **渲染小程序首页**。微信客户端通过`app.json` 的 `pages` 字段知道当前小程序的所有页面路径。通过小程序底层的一些机制,微信客户端就把首页的代码装载并渲染出首页。 3. **执行onLaunch 回调**。小程序启动之后,在`app.js` 定义的 `App` 实例的 `onLaunch` 回调会被执行。整个小程序只有一个 App 实例,是全部页面共享的。 4. **界面生成**。微信客户端根据页面的`*.json` 配置文件生成一个界面。顶部的颜色和文字都可以在这个 json 文件里边定义好。 5. **装载页面结构、样式**。微信客户端装载页面的`*.wxml`文件生成页面结构,装载页面的`*.wxss`文件显示页面结构。 6. **渲染生成页面**。微信客户端装载页面的`*.js`文件,根据文件里的页面构造器`Page `生成页面。在生成页面的时候,小程序框架会把`Page `里的 `data` 数据结合页面的`*.wxml`文件一起渲染出最终的页面。 7. **执行onLoad 回调**。在渲染完页面之后,页面实例(`Page `)就会收到一个 onLoad 的回调,可以在这个回调处理一些业务逻辑。 小程序启动会有两种情况 * **冷启动** 用户首次打开小程序或小程序被微信主动销毁后再次打开的情况,此时小程序需要重新加载启动。 * **热启动** 用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时小程序无需重新启动,只需将后台态的小程序切换到前台。 **更新机制** 小程序冷启动时如果发现有新版本,将会异步下载新版本的代码包,并同时用客户端本地的包进行启动,即新版本的小程序需要等下一次冷启动才会应用上。 如果需要马上应用最新版本,可以使用 `wx.getUpdateManager` API 进行处理。 **运行机制** * 小程序没有重启的概念 * 当小程序进入后台,微信客户端会维持一段时间小程序的运行状态,超过一定时间后小程序(目前是5分钟)会被微信客户端主动销毁 * 当短时间内(5s)微信客户端连续收到两次以上系统内存告警,微信客户端会进行小程序的销毁 **再次打开逻辑** 用户打开小程序的预期有以下两类场景: A. 打开首页: 场景值有 1001(发现栏小程序主入口,“最近使用”列表), 1019(微信钱包), 1022(聊天顶部置顶小程序入口), 1023(安卓系统桌面图标), 1038(从另一个小程序返回), 1056(音乐播放器菜单) B. 打开小程序指定的某个页面: 场景值为除 A 以外的其他 | 上一次的场景 | 当前打开的场景 | 效果 | | --- | --- | --- | | A | A | 保留原来的状态 | | B | A | 清空原来的页面栈,打开首页(相当于执行 wx.reLaunch 到首页) | | A 或 B | B | 清空原来的页面栈,打开指定页面(相当于执行 wx.reLaunch 到指定页) | ## 2.1 渲染层和逻辑层 小程序的运行环境分成`渲染层`和`逻辑层`, 小程序的渲染层和逻辑层分离是经过很多考虑得出来的模型。 WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。 1. `渲染层`(WXML、WXSS文件)和数据相关。即:怎样表现数据(`Show Data`)。 2. `逻辑层`(js文件)负责产生、处理数据。即:什么样的数据(`What Data`)。 3. `逻辑层`(js文件)通过 Page 实例的 setData 方法传递数据到渲染层。即:怎么传递数据(`Send Data`)。 ### 2.1.1 通信模型 小程序的渲染层和逻辑层分别由2个线程管理: - 渲染层的界面使用了`WebView` 进行渲染; - 逻辑层采用`JsCore`线程运行JS脚本。 一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端(下文中也会采用Native来代指微信客户端)做中转,逻辑层发送网络请求也经由Native转发。 ### 2.1.2 数据驱动 在开发UI界面过程中,通常界面视图和变量状态是相关联的,可以通过`数据驱动`这种机制将状态和视图绑定在一起(状态变更时,视图也能自动变更),那我们就可以省去大量手动修改视图的工作。 小程序的WXML结构实际上等价于一棵Dom树,同时通过一个JS对象也可以来表达Dom树的结构。 WXML可以先转成JS对象,然后再渲染出真正的Dom树。 >[info] HY:小程序数据驱动要点 > 1. JS对象 > 2. DOM树 > 3. JS对象发生变化就会引起DOM树的变化 ### 2.1.3 双线程下的界面渲染 小程序的逻辑层和渲染层是分开的两个线程。 在渲染层,宿主环境会把WXML转化成对应的JS对象,在逻辑层发生数据变更的时候,我们需要通过宿主环境提供的`setData`方法把数据从逻辑层传递到渲染层,再经过对比前后差异,把差异应用在原来的Dom树上,渲染出正确的UI界面。 ## 2.2 程序与页面 从逻辑组成来说,一个小程序是由多个·`页面`组成的`程序`。 而通常`程序`在启动或者退出的时候存储数据或者在“页面”显示或者隐藏的时候做一些逻辑处理。 ### 2.2.1 程序 **1. 程序构造器`App()`** 宿主环境(客户端)提供了`App()` 构造器用来注册一个程序App,需要留意的是`App()` 构造器必须写在项目根目录的app.js里,App实例是单例对象,在其他JS脚本中可以使用宿主环境提供的 `getApp()` 来获取程序实例。 :-: 表3-1 App构造器的参数 | 参数属性 | 类型 | 描述| | --- | --- | --- | | onLaunch | Function | 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)| | onShow | Function | 当小程序启动,或从后台进入前台显示,会触发 onShow | | onHide | Function | 当小程序从前台进入后台,会触发 onHide | | onError | Function | 当小程序发生脚本错误,或者 API 调用失败时,会触发 onError 并带上错误信息 | | 其他字段   | 任意 | 可以添加任意的函数或数据到 Object 参数中,在App实例回调用 this 可以访问 | 2. 程序的生命周期和打开场景 初次进入小程序的时候,微信客户端初始化好宿主环境,同时从网络下载或者从本地缓存中拿到小程序的代码包,把它注入到宿主环境,初始化完毕后,微信客户端就会给App实例派发onLaunch事件,App构造器参数所定义的`onLaunch`方法会被调用。 进入小程序之后,用户可以点击左上角的关闭,或者按手机设备的Home键离开小程序,此时小程序并没有被直接销毁,我们把这种情况称为“小程序进入后台状态”,App构造器参数所定义的`onHide`方法会被调用。 当再次回到微信或者再次打开小程序时,微信客户端会把“后台”的小程序唤醒,我们把这种情况称为“小程序进入前台状态”,App构造器参数所定义的`onShow`方法会被调用。 App的生命周期是由微信客户端根据用户操作主动触发的。为了避免程序上的混乱,我们不应该从其他代码里主动调用App实例的生命周期函数。 在微信客户端中打开小程序有很多途径: * 从群聊会话里打开 * 从小程序列表中打开 * 通过微信扫一扫二维码打开 * 从另外一个小程序打开当前小程序等 针对不同途径的打开方式,小程序有时需要做不同的业务处理,所以微信客户端会把打开方式带给onLaunch和onShow的调用参数`options`。需要留意小程序的宿主环境在迭代更新过程会增加不少打开场景,因此要获取最新的场景值说明请查看官方文档:https://mp.weixin.qq.com/debug/wxadoc/dev/framework/app-service/app.html。 :-: 表3-2 onLaunch,onShow参数 | 字段 | 类型 | 描述 | | --- |--- | ---| | path | String | 打开小程序的页面路径 | | query | Object | 打开小程序的页面参数query | | scene | Number | 打开小程序的场景值,详细场景值请参考小程序官方文档 | | shareTicket | String | shareTicket,详见小程序官方文档 | | referrerInfo | Object | 当场景为由从另一个小程序或公众号或App打开时,返回此字段 | | referrerInfo.appId | String | 来源小程序或公众号或App的 appId,详见下方说明 | | referrerInfo.extraData | Object | 来源小程序传过来的数据,scene=1037或1038时支持 | :-: 表3-3 以下场景支持返回 referrerInfo.appId | 场景值 | 场景 | appId信息含义 | | --- |--- | ---| | 1020 | 公众号 profile | 页相关小程序列表 返回来源公众号 appId | 1035 | 公众号自定义菜单 | 返回来源公众号 appId | 1036 | App 分享消息卡片 | 返回来源应用 appId | 1037 | 小程序打开小程序 | 返回来源小程序 appId | 1038 | 从另一个小程序返回 | 返回来源小程序 appId | 1043 | 公众号模板消息 | 返回来源公众号 appId 3. 小程序全局数据 小程序的JS脚本是运行在JsCore的线程里,小程序的每个页面各自有一个WebView线程进行渲染,所以小程序切换页面时,小程序逻辑层的JS脚本运行上下文依旧在同一个JsCore线程中。 小程序的App实例是单例的,因此不同页面直接可以通过App实例下的属性来共享数据。 >[danger] App构造器可以传递其他参数作为全局属性以达到全局共享数据的目的。 >[danger] 由于所有页面的脚本逻辑都跑在同一个JsCore线程,页面使用setTimeout或者setInterval的定时器,然后跳转到其他页面时,这些定时器并没有被清除,需要开发者自己在页面离开的时候进行清理。 ### 2.2.2 页面 一个小程序可以有很多页面,每个页面承载不同的功能,页面之间可以互相跳转。 1. 页面的文件构成和路径 一个页面是分三部分组成: * 界面:`WXML`文件和`WXSS`文件描述 * 配置:由`JSON`文件进行描述 * 逻辑:`JS`脚本文件负责 >[danger] 一个页面的文件需要放置在同一个目录下,其中WXML文件和JS文件是必须存在的,JSON和WXSS文件是可选的。 >[danger] 页面路径需要在小程序代码根目录app.json中的pages字段声明,否则这个页面不会被注册到宿主环境中。 **2. 页面构造器`Page()`** 宿主环境提供了` Page()` 构造器用来注册一个小程序页面,Page()在页面脚本page.js中调用,Page构造器接受一个Object参数,参数说明如表3-4所示。 * 初始数据: `data`属性是当前页面WXML模板中可以用来做数据绑定的初始数据; * 生命周期函数:`onLoad / onReady / onShow / onHide /onUnload` 5个回调是Page实例的生命周期函数; * 用户行为: `onPullDownRefresh / onReachBottom / onShareAppMessage / onPageScroll` 4个回调是页面的用户行为。 :-: 表3-4 Page构造器的参数 | 参数属性 | 类型 | 描述 | | --- |--- | --- | | data | Object | 页面的初始数据 | | onLoad | Function | 生命周期函数--监听页面加载,触发时机早于onShow和onReady | | onReady | Function | 生命周期函数--监听页面初次渲染完成 | | onShow | Function | 生命周期函数--监听页面显示,触发事件早于onReady | | onHide | Function | 生命周期函数--监听页面隐藏 | | onUnload | Function | 生命周期函数--监听页面卸载 | | onPullDownRefresh | Function | 页面相关事件处理函数--监听用户下拉动作 | | onReachBottom | Function | 页面上拉触底事件的处理函数 | | onShareAppMessage | Function | 用户点击右上角转发 | | onPageScroll | Function | 页面滚动触发事件的处理函数 | | 其他 | Any | 可以添加任意的函数或数据,在Page实例的其他函数中用 this 可以访问 | 3. 页面的生命周期和打开参数 页面初次加载的时候,微信客户端就会给Page实例派发onLoad事件,Page构造器参数所定义的`onLoad`方法会被调用,onLoad在页面没被销毁之前只会触发1次,在onLoad的回调中,可以获取当前页面所调用的打开参数option。 页面显示之后,Page构造器参数所定义的`onShow`方法会被调用,一般从别的页面返回到当前页面时,当前页的onShow方法都会被调用。 在页面初次渲染完成时,Page构造器参数所定义的`onReady`方法会被调用,onReady在页面没被销毁前只会触发1次,onReady触发时,表示页面已经准备妥当,在逻辑层就可以和视图层进行交互了。 以上三个事件触发的时机是onLoad早于 onShow,onShow早于onReady。 页面不可见时,Page构造器参数所定义的`onHide`方法会被调用,这种情况会在使用`wx.naviagteTo`切换到其他页面、底部tab切换时触发。 当前页面使用wx.redirectTo或wx.navigateBack返回到其他页时,当前页面会被微信客户端销毁回收,此时Page构造器参数所定义的`onUnload`方法会被调用。 上述5个Page的生命周期函数/方法是由微信客户端根据用户操作主动触发的。为了避免程序上的混乱,我们不应该在其他代码中主动调用Page实例的生命周期函数。 * 页面的打开参数 使用场景举例:购物商城的小程序,一个商品列表页和商品详情页,点击商品列表页的商品就可以跳转到该商品的详情页。 当然我们不可能为每个商品单独去实现它的详情页。我们只需要实现一个商品详情页的pages/detail/detail.(代表WXML/WXSS/JS/JSON文件)即可,在列表页打开商品详情页时把商品的id传递过来,详情页通过刚刚说的onLoad回调的参数option就可以拿到商品id,从而绘制出对应的商品 小程序把页面的打开路径定义成页面URL,其组成格式和网页的URL类似,在页面路径后使用英文 ? 分隔path和query部分。 * query部分:多个参数使用 `&` 进行分隔,参数的名字和值使用 key=value 的形式声明。 在页面Page构造器里onLoad的option可以拿到当前页面的打开参数,其类型是一个Object,其键值对与页面URL上query键值对一一对应。 和网页URL一样,页面URL上的value如果涉及特殊字符(例如:`&`字符、`?`字符、`中文`字符等,详情参考URI的RFC3986说明 ),需要采用UrlEncode后再拼接到页面URL上。 4. 页面的数据 小程序的页面结构由WXML进行描述,WXML可以通过数据绑定的语法绑定从逻辑层传递过来的数据字段(页面Page构造器的data字段,data参数是页面第一次渲染时从逻辑层传递到渲染层的数据)。 宿主环境所提供的Page实例的原型中有`setData`函数,我们可以在Page实例下的方法调用`this.setData`把数据传递给渲染层,从而达到更新界面的目的。 由于小程序的渲染层和逻辑层分别在两个线程中运行,所以setData传递数据实际是一个异步的过程,所以setData的第二个参数是一个callback回调,在这次setData对界面渲染完毕后触发。 setData其一般调用格式是 setData(data, callback),其中data是由多个key: value构成的Object对象。 5. 页面的用户行为 小程序宿主环境提供了四个和页面相关的用户行为回调: * 下拉刷新 `onPullDownRefresh` * 上拉触底 `onReachBottom` * 页面滚动` onPageScroll` * 用户转发 `onShareAppMessage` 6. 页面跳转和路由 一个小程序拥有多个页面,我们可以通过`wx.navigateTo`推入一个新的页面。在首页使用2次wx.navigateTo后,页面层级会有三层,我们把这样的一个页面层级称为`页面栈`。 页面栈描述:\[ pageA, pageB, pageC ],其中pageA在最底下,pageC在最顶上,也就是用户所看到的界面。小程序宿主环境限制了这个页面栈的最大层级为10层 ,也就是当页面栈到达10层之后就没有办法再推入新的页面了。 和导航相关的API: * `wx.navigateTo({ url: 'pageD' })`: 可以往当前页面栈多推入一个 pageD,只能打开非TabBar页面。 * `wx.navigateBack()` 可以退出当前页面栈的最顶上页面。 * `wx.redirectTo({ url: 'pageE' })` 是替换当前页变成pageE,当页面栈到达10层没法再新增的时候,往往就是使用redirectTo这个API进行页面跳转。只能打开非TabBar页面。 * `wx.switchTab({ url: 'pageF' })`,此时原来的页面栈会被清空(除了已经声明为Tabbar页的pageA外其他页面会被销毁),然后会切到pageF所在的tab页面,页面栈变成 \[ pageF ],此时点击Tab1切回到pageA时,pageA不会再触发onLoad,因为pageA没有被销毁。 * `wx. reLaunch({ url: 'pageH' })` 重启小程序,并且打开pageH,此时页面栈为 \[ pageH ]。 >[danger] `wx.navigateTo`和`wx.redirectTo`只能打开非TabBar页面, >`wx.switchTab`只能打开Tabbar页面。 小程序提供了原生的`Tabbar`支持,我们可以在`app.json`声明tabBar字段来定义Tabbar页(注:更多详细参数见Tabbar官方文档 )。 :-: 表3-5页面路由触发方式及页面生命周期函数的对应关系。 | 路由方式 | 触发时机 | 路由前页面生命周期 | 路由后页面生命周期 | | --- | --- | --- | --- | | 初始化 | 小程序打开的第一个页面 | | onLoad, onShow | | 打开新页面 | 调用 | API wx.navigateTo | onHide | onLoad, onShow | | 页面重定向 | 调用 | API wx.redirectTo | onUnload | onLoad, onShow | | 页面返回 | 调用 | API wx.navigateBack | onUnload | onShow | | Tab | 切换 调用 | API wx.switchTab | 请参考表3-6 | 请参考表3-6 | | 重启动 | 调用 | API wx.reLaunch | onUnload | onLoad, onShow | :-: 表3-6 页面路由触发方式及页面生命周期函数的对应关系 | 当前页面 | 路由后页面 | 触发的生命周期(按顺序)| | --- | --- | --- | | A | A | 无 | | A | B | A.onHide(), B.onLoad(), B.onShow() | | A | B(再次打开) | A.onHide(), B.onShow() | | C | A | C.onUnload(), A.onShow() | | C | B | C.onUnload(), B.onLoad(), B.onShow() | | D | B | D.onUnload(), C.onUnload(), B.onLoad(), B.onShow() | | D(从转发进入) | A | D.onUnload(), A.onLoad(), A.onShow() | | D(从转发进入) | B | D.onUnload(), B.onLoad(), B.onShow() | Tab 切换对应的生命周期(以 A、B 页面为 Tabbar 页面,C 是从 A 页面打开的页面,D 页面是从 C 页面打开的页面为例)如表3-6所示,注意Tabbar页面初始化之后不会被销毁。 ## 2.3 组件 一个小程序页面可以分解成多个部分组成,组件就是小程序页面的基本组成单元。小程序的宿主环境提供了一系列基础组件。 组件说明 https://mp.weixin.qq.com/debug/wxadoc/dev/component/。 组件是在WXML模板文件声明中使用的,WXML的语法和HTML语法相似,小程序使用标签名来引用一个组件,通常包含开始标签和结束标签,该标签的属性用来描述该组件。 >[danger]所有组件名和属性都是小写,多个单词会以英文横杠 "-" 进行连接。 所有组件都拥有表3-7列举的属性,主要涉及样式和事件绑定。 :-: 表3-7 组件共有属性 | 属性名 | 类型 | 描述 | 其他说明 | | --- | --- | --- | --- | | id | String | 组件的唯一标示 | 保持整个页面唯一 | | class | String | 组件的样式类 | 在对应的WXSS中定义的样式类 | | style | String | 组件的内联样式 | 可以通过数据绑定进行动态设置的内联样式| | hidden | Boolean | 组件是否显示 | 所有组件默认显示| | data-* | Any | 自定义属性 | 组件上触发的事件时,会发送给事件处理函数 | | bind /catch | EventHandler | 事件 | 详情见`2.5节 事件` | 组件都拥有各自自定义的属性,可以对该组件的功能或者样式进行修饰。 ## 2.4 API 宿主环境提供了丰富的API,可以很方便调用微信提供的能力。几乎所有小程序的API都挂载在wx对象底下(除了Page/App等特殊的构造器)。 小程序提供的API按照功能主要分为几大类:网络、媒体、文件、数据缓存、位置、设备、界面、界面节点信息还有一些特殊的开放接口,API一般调用的约定: 1. wx.on* 开头的 API 是监听某个事件发生的API接口,接受一个 Callback 函数作为参数。当该事件触发时,会调用 Callback 函数。 2. 如未特殊约定,多数 API 接口为异步接口 ,都接受一个Object作为参数。 3. API的Object参数一般由success、fail、complete三个回调来接收接口调用结果,示例代码如代码清单3-17所示,详细说明如表3-9所示。 4. wx.get* 开头的API是获取宿主环境数据的接口。 5. wx.set* 开头的API是写入数据到宿主环境的接口。 :-: 表3-9 API接口回调说明 | 参数名字 | 类型 | 必填 | 描述 | | --- | --- | --- | --- | | success | Function | 否 | 接口调用成功的回调函数| | fail | Function | 否 | 接口调用失败的回调函数| | complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行)| >[info] * API调用大多都是异步的, >* 有部分API会拉起微信的原生界面,此时会触发Page的`onHide`方法,当用户从原生界面返回到小程序时,会触发Page的`onShow`方法。 API的数量非常多,而且随着宿主环境的迭代更新会持续新增API,了解一般调用API的技巧,再通过[【官方API文档】 ](https://mp.weixin.qq.com/debug/wxadoc/dev/api/)了解到对应的API参数细节即可。 ## 2.5 事件 在小程序里,把“用户在渲染层的行为反馈”以及“组件的部分状态反馈”抽象为渲染层传递给逻辑层的“事件”。 1. 组件绑定事件处理函数。wxml文件中,事件是通过`bindtap`这个属性绑定在组件上的。 2. 定义事件处理函数。js文件中,在当前页面的Page构造器中定义对应的事件处理函数`tapName`; 3. 触发事件。当用户点击该view区域时,达到触发条件生成事件`tap`,该事件处理函数tapName会被执行,同时还会收到一个事件对象event。 ### 2.5.1 事件类型和事件对象 组件的事件可以参考其参数说明,详情见[【官方文档】](https://mp.weixin.qq.com/debug/wxadoc/dev/component/ ) 常见的用户事件类型如表3-10所示。 :-: 表3-10 常见的冒泡事件类型 | 类型 | 触发条件 | | --- | --- | | touchstart | 手指触摸动作开始| | touchmove | 手指触摸后移动| | touchcancel | 手指触摸动作被打断,如来电提醒,弹窗| | touchend | 手指触摸动作结束| | tap | 手指触摸后马上离开| | longpress | 手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发| | longtap | 手指触摸后,超过350ms再离开(推荐使用longpress事件代替)| | transitionend | 会在 WXSS transition 或 wx.createAnimation 动画结束后触发| | animationstart | 会在一个 WXSS animation 动画开始时触发| | animationiteration | 会在一个 WXSS animation 一次迭代结束时触发| | animationend | 会在一个 WXSS animation 动画完成时触发| 当事件回调触发的时候,会收到一个事件对象,对象的详细属性如下表所示。 :-: 表3-11 事件对象属性 | 属性 | 类型 | 说明| | --- | ---| ---| | type | String | 事件类型| | timeStamp | Integer | 页面打开到触发事件所经过的毫秒数| | target | Object | 触发事件的组件的一些属性值集合| | currentTarget | Object | 当前组件的一些属性值集合| | detail | Object | 额外的信息| | touches | Array | 触摸事件,当前停留在屏幕中的触摸点信息的数组| | changedTouches | Array | 触摸事件,当前变化的触摸点信息的数组| `currentTarget`为当前事件所绑定的组件, `target`则是触发该事件的源头组件。 :-: 表3-12 target和currentTarget事件对象属性 | 属性 | 类型 | 说明| | --- | ---| ---| | id | String | 当前组件的id| | tagName | String | 当前组件的类型| | dataset | Object | 当前组件上由data-开头的自定义属性组成的集合| :-: 表3-13 touch和changedTouches对象属性 | 属性 | 类型 | 说明| | --- | ---| ---| | identifier | Number | 触摸点的标识符| | pageX, pageY | Number | 距离文档左上角的距离,文档的左上角为原点 ,横向为X轴,纵向为Y轴| | clientX, clientY | Number | 距离页面可显示区域(屏幕除去导航条)左上角距离,横向为X轴,纵向为Y轴| ### 2.5.2 事件绑定与冒泡捕获 事件绑定的写法和组件属性一致,以`key="value"`的形式,其中: 1. **`key`以bind或者catch开头,然后跟上事件的类型**,如`bindtap`、`catchtouchstart`。 自基础库版本1.5.0起,bind和catch后可以紧跟一个冒号,其含义不变,如`bind:tap`、`catch:touchstart`。同时bind和catch前还可以加上`capture-`来表示捕获阶段。 2. **`value`是一个字符串**,需要在对应的页面Page构造器中定义同名的函数,否则触发事件时在控制台会有报错信息。 3. `bind`和`capture-bind`的含义分别代表事件的冒泡阶段和捕获阶段 >bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡。 注意,除表3-10列举的事件类型之外的其他组件自定义事件,如无特殊声明都是非冒泡事件,如\<form/>的submit事件,\<input/>的input事件,\<scroll-view/>的scroll事件。 ## 2.6 兼容 1. **使用 `wx.getSystemInfo` 或者 `wx.getSystemInfoSync`** API来获取手机品牌、操作系统版本号、微信版本号以及小程序基础库版本号等,通过这个信息,我们可以针对不同平台做差异化的服务。 2. **判断API是否存在**来做程序上的兼容。 3. **使用`wx.canIUse`** API,用于判断接口或者组件在当前宿主环境是否可用,其参数格式为: `${API}.${method}.${param}.${options}或者${component}.${attribute}.${option}` 各个段的含义如下: * ${API} 代表 API 名字 * ${method} 代表调用方式,有效值为return, success, object, callback * ${param} 代表参数或者返回值 * ${options} 代表参数的可选值 * ${component} 代表组件名字 * ${attribute} 代表组件属性 * ${option} 代表组件属性的可选值 我们可以选择合适的判断方法来做小程序的向前兼容,以保证我们的小程序在旧版本的微信客户端也能工作正常。 在不得已的情况下(小程序强依赖某个新的API或者组件时),还可以通过在小程序管理后台设置“基础库最低版本设置”来达到不向前兼容的目的。 例如你选择设置你的小程序只支持1.5.0版本以上的宿主环境,那么当运行着1.4.0版本宿主环境的微信用户打开你的小程序的时候,微信客户端会显示当前小程序不可用,并且提示用户应该去升级微信客户端。