微信小程序框架模板(微信小程序框架)
框架
小程序开发框架的目标是通过尽可能简单 、高效的方式让开发者可以在微信中开发具有原生 APP 体验的服务 。
整个小程序框架系统分为两部分:逻辑层(App Service)和 视图层(View) 。小程序提供了自己的视图层描述语言 WXML 和 WXSS ,以及基于 JavaScript 的逻辑层框架 ,并在视图层与逻辑层间提供了数据传输和事件系统 ,让开发者能够专注于数据与逻辑 。
响应的数据绑定
框架的核心是一个响应的数据绑定系统 ,可以让数据与视图非常简单地保持同步 。当做数据修改的时候 ,只需要在逻辑层修改数据 ,视图层就会做相应的更新 。
通过这个简单的例子来看:
在开发者工具中预览效果
<!-- This is our View --> <view> Hello {{name}}! </view> <button bindtap="changeName"> Click me! </button> // This is our App Service. // This is our data. var helloData = { name: Weixin } // Register a Page. Page({ data: helloData, changeName: function(e) { // sent data change to view this.setData({ name: MINA }) } })开发者通过框架将逻辑层数据中的 name 与视图层的 name 进行了绑定 ,所以在页面一打开的时候会显示 Hello Weixin!;
当点击按钮的时候 ,视图层会发送 changeName 的事件给逻辑层 ,逻辑层找到并执行对应的事件处理函数;
回调函数触发后 ,逻辑层执行 setData 的操作 ,将 data 中的 name 从 Weixin 变为 MINA ,因为该数据和视图层已经绑定了,从而视图层会自动改变为 Hello MINA! 。
页面管理
框架 管理了整个小程序的页面路由 ,可以做到页面间的无缝切换 ,并给以页面完整的生命周期 。开发者需要做的只是将页面的数据 、方法 、生命周期函数注册到 框架 中,其他的一切复杂的操作都交由 框架 处理 。
基础组件
框架 提供了一套基础的组件 ,这些组件自带微信风格的样式以及特殊的逻辑 ,开发者可以通过组合基础组件 ,创建出强大的微信小程序 。
丰富的 API
框架 提供丰富的微信原生 API ,可以方便的调起微信提供的能力 ,如获取用户信息 ,本地存储 ,支付功能等 。
逻辑层 App Service
小程序开发框架的逻辑层使用 JavaScript 引擎为小程序提供开发者 JavaScript 代码的运行环境以及微信小程序的特有功能 。
逻辑层将数据进行处理后发送给视图层 ,同时接受视图层的事件反馈 。
开发者写的所有代码最终将会打包成一份 JavaScript 文件 ,并在小程序启动的时候运行 ,直到小程序销毁。这一行为类似 ServiceWorker ,所以逻辑层也称之为 App Service 。
在 JavaScript 的基础上 ,我们增加了一些功能,以方便小程序的开发:
增加 App 和 Page 方法 ,进行程序注册和页面注册 。
增加 getApp 和 getCurrentPages 方法 ,分别用来获取 App 实例和当前页面栈。
提供丰富的 API,如微信用户数据 ,扫一扫 ,支付等微信特有能力 。
提供模块化能力 ,每个页面有独立的作用域 。
注意:小程序框架的逻辑层并非运行在浏览器中 ,因此 JavaScript 在 web 中一些能力都无法使用 ,如 window ,document 等 。
小程序的生命周期
每个小程序都需要在 app.js 中调用 App 方法注册小程序实例 ,绑定生命周期回调函数 、错误监听和页面不存在监听函数等 。
详细的参数含义和使用请参考 App 参考文档 。
// app.js App({ onLaunch (options) { // Do something initial when launch. }, onShow (options) { // Do something when show. }, onHide () { // Do something when hide. }, onError (msg) { console.log(msg) }, globalData: I am global data })整个小程序只有一个 App 实例 ,是全部页面共享的 。开发者可以通过 getApp 方法获取到全局唯一的 App 实例 ,获取 App 上的数据或调用开发者注册在 App 上的函数 。
// xxx.js const appInstance = getApp() console.log(appInstance.globalData) // I am global data前台 、后台定义: 当用户点击左上角关闭 ,或者按了设备 Home 键离开微信 ,小程序并没有直接销毁 ,而是进入了后台;当再次进入微信或再次打开小程序,又会从后台进入前台 。
只有当小程序进入后台一定时间 ,或者系统资源占用过高 ,才会被真正的销毁 。
注意:
1.不要在定义于 App() 内的函数中调用 getApp() ,使用 this 就可以拿到 app 实例 。
2.不要在 onLaunch 的时候调用 getCurrentPage() ,此时 page 还没有生成 。
3.通过 getApp() 获取实例之后 ,不要私自调用生命周期函数 。
注册页面
对于小程序中的每个页面 ,都需要在页面对应的 js 文件中进行注册 ,指定页面的初始数据 、生命周期回调 、事件处理函数等。
使用 Page 构造器注册页面
简单的页面可以使用 Page() 进行构造 。
代码示例:
//index.js Page({ data: { text: "This is page data." }, onLoad: function(options) { // 页面创建时执行 }, onShow: function() { // 页面出现在前台时执行 }, onReady: function() { // 页面首次渲染完毕时执行 }, onHide: function() { // 页面从前台变为后台时执行 }, onUnload: function() { // 页面销毁时执行 }, onPullDownRefresh: function() { // 触发下拉刷新时执行 }, onReachBottom: function() { // 页面触底时执行 }, onShareAppMessage: function () { // 页面被用户分享时执行 }, onPageScroll: function() { // 页面滚动时执行 }, onResize: function() { // 页面尺寸变化时执行 }, onTabItemTap(item) { // tab 点击时执行 console.log(item.index) console.log(item.pagePath) console.log(item.text) }, // 事件响应函数 viewTap: function() { this.setData({ text: Set some data for updating view. }, function() { // this is setData callback }) }, // 自由数据 customData: { hi: MINA } })详细的参数含义和使用请参考 Page 参考文档 。
在页面中使用 behaviors
基础库 2.9.2 开始支持 ,低版本需做兼容处理。
页面可以引用 behaviors 。 behaviors 可以用来让多个页面有相同的数据字段和方法 。
// my-behavior.js module.exports = Behavior({ data: { sharedText: This is a piece of data shared between pages. }, methods: { sharedMethod: function() { this.data.sharedText === This is a piece of data shared between pages. } } }) // page-a.js var myBehavior = require(./my-behavior.js) Page({ behaviors: [myBehavior], onLoad: function() { this.data.sharedText === This is a piece of data shared between pages. } })具体用法参见 behaviors 。
使用 Component 构造器构造页面
基础库 1.6.3 开始支持 ,低版本需做兼容处理 。
Page 构造器适用于简单的页面 。但对于复杂的页面 , Page 构造器可能并不好用 。
此时 ,可以使用 Component 构造器来构造页面 。 Component 构造器的主要区别是:方法需要放在 methods: { } 里面 。
代码示例:
Component({ data: { text: "This is page data." }, methods: { onLoad: function(options) { // 页面创建时执行 }, onPullDownRefresh: function() { // 下拉刷新时执行 }, // 事件响应函数 viewTap: function() { // ... } } })这种创建方式非常类似于 自定义组件 ,可以像自定义组件一样使用 behaviors 等高级特性 。
具体细节请阅读 Component 构造器 章节 。
页面的生命周期
下图说明了页面 Page 实例的生命周期 。
写微信小程序 ,他的生命周期不能不知道 ,不知道小程序就会出现各种bug而无法解决 。
小程序由两大线程组成:负责界面的线程(view thread)和服务线程(appservice thread) ,各司其职由互相配合
页面路由
在小程序中所有页面的路由全部由框架进行管理。
页面栈
框架以栈的形式维护了当前的所有页面 。 当发生路由切换的时候,页面栈的表现如下:
路由方式 页面栈表现 初始化 新页面入栈 打开新页面 新页面入栈 页面重定向 当前页面出栈 ,新页面入栈 页面返回 页面不断出栈 ,直到目标返回页 Tab 切换 页面全部出栈,只留下新的 Tab 页面 重加载 页面全部出栈 ,只留下新的页面开发者可以使用 getCurrentPages() 函数获取当前页面栈 。
路由方式
对于路由的触发方式以及页面生命周期函数如下:
路由方式 触发时机 路由前页面 路由后页面 初始化 小程序打开的第一个页面 onLoad, onShow 打开新页面 调用 API wx.navigateTo 使用组件 `` onHide onLoad, onShow 页面重定向 调用 API wx.redirectTo 使用组件 `` onUnload onLoad, onShow 页面返回 调用 API wx.navigateBack 使用组件`` 用户按左上角返回按钮 onUnload onShow Tab 切换 调用 API wx.switchTab 使用组件 `` 用户切换 Tab 各种情况请参考下表 重启动 调用 API wx.reLaunch 使用组件 `` onUnload onLoad, onShowTab 切换对应的生命周期(以 A 、B 页面为 Tabbar 页面 ,C 是从 A 页面打开的页面 ,D 页面是从 C 页面打开的页面为例):
当前页面 路由后页面 触发的生命周期(按顺序) A A Nothing happend 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()注意事项
navigateTo, redirectTo 只能打开非 tabBar 页面。
a--navigateTo--c, c-->redirectTo-->d
switchTab 只能打开 tabBar 页面 。
reLaunch 可以打开任意页面 。
页面底部的 tabBar 由页面决定 ,即只要是定义为 tabBar 的页面 ,底部都有 tabBar 。
调用页面路由带的参数可以在目标页面的onLoad中获取 。
模块化
模块化
可以将一些公共的代码抽离成为一个单独的 js 文件 ,作为一个模块 。模块只有通过 module.exports 或者 exports 才能对外暴露接口 。
注意:
exports 是 module.exports 的一个引用 ,因此在模块里边随意更改 exports 的指向会造成未知的错误 。所以更推荐开发者采用 module.exports 来暴露模块接口 ,除非你已经清晰知道这两者的关系 。
小程序目前不支持直接引入 node_modules , 开发者需要使用到 node_modules 时候建议拷贝出相关的代码到小程序的目录中 ,或者使用小程序支持的 npm 功能 。
// common.js function sayHello(name) { console.log(`Hello ${name} !`) } function sayGoodbye(name) { console.log(`Goodbye ${name} !`) } module.exports.sayHello = sayHello exports.sayGoodbye = sayGoodbye 在需要使用这些模块的文件中 ,使用 require 将公共代码引入;也可以使用import导入 var common = require(common.js) Page({ helloMINA: function() { common.sayHello(MINA) }, goodbyeMINA: function() { common.sayGoodbye(MINA) } })文件作用域
在 JavaScript 文件中声明的变量和函数只在该文件中有效;不同的文件中可以声明相同名字的变量和函数 ,不会互相影响 。
通过全局函数 getApp 可以获取全局的应用实例 ,如果需要全局的数据可以在 App() 中设置,如:
// app.js App({ globalData: 1 }) // a.js // The localValue can only be used in file a.js. var localValue = a // Get the app instance. var app = getApp() // Get the global data and change it. app.globalData++ // b.js // You can redefine localValue in file b.js, without interference with the localValue in a.js. var localValue = b // If a.js it run before b.js, now the globalData shoule be 2. console.log(getApp().globalData)API
小程序开发框架提供丰富的微信原生 API ,可以方便的调起微信提供的能力 ,如获取用户信息,本地存储 ,支付功能等 。详细介绍请参考 API 文档 。
通常 ,在小程序 API 有以下几种类型:
事件监听 API
我们约定 ,以 on 开头的 API 用来监听某个事件是否触发 ,如:wx.onSocketOpen ,wx.onCompassChange 等。
这类 API 接受一个回调函数作为参数 ,当事件触发时会调用这个回调函数 ,并将相关数据以参数形式传入 。
代码示例
wx.onCompassChange(function (res) { console.log(res.direction) })同步 API
我们约定 ,以 Sync 结尾的 API 都是同步 API , 如 wx.setStorageSync ,wx.getSystemInfoSync 等 。此外 ,也有一些其他的同步 API ,如 wx.createWorker,wx.getBackgroundAudioManager 等 ,详情参见 API 文档中的说明。
同步 API 的执行结果可以通过函数返回值直接获取 ,如果执行出错会抛出异常 。
代码示例
try { wx.setStorageSync(key, value) } catch (e) { console.error(e) }异步 API
大多数 API 都是异步 API,如 wx.request ,wx.login 等 。这类 API 接口通常都接受一个 Object 类型的参数 ,这个参数都支持按需指定以下字段来接收接口调用结果:
Object 参数说明
参数名 类型 必填 说明 success function 否 接口调用成功的回调函数 fail function 否 接口调用失败的回调函数 complete function 否 接口调用结束的回调函数(调用成功 、失败都会执行) 其他 Any - 接口定义的其他参数回调函数的参数
success ,fail ,complete 函数调用时会传入一个 Object 类型参数 ,包含以下字段:
属性 类型 说明 errMsg string 错误信息 ,如果调用成功返回 ${apiName}:ok errCode number 错误码 ,仅部分 API 支持 ,具体含义请参考对应 API 文档 ,成功时为 0 。 其他 Any 接口返回的其他数据异步 API 的执行结果需要通过 Object 类型的参数中传入的对应回调函数获取 。部分异步 API 也会有返回值 ,可以用来实现更丰富的功能 ,如 wx.request ,wx.connectSocket 等 。
代码示例
wx.login({ success(res) { console.log(res.code) } })异步 API 返回 Promise
基础库 2.10.2 版本起,异步 API 支持 callback & promise 两种调用方式 。当接口参数 Object 对象中不包含 success/fail/complete 时将默认返回 promise ,否则仍按回调方式执行 ,无返回值 。
注意事项
部分接口如 downloadFile, request, uploadFile, connectSocket, createCamera(小游戏)本身就有返回值, 它们的 promisify 需要开发者自行封装 。
当没有回调参数时 ,异步接口返回 promise 。此时若函数调用失败进入 fail 逻辑 , 会报错提示 Uncaught (in promise) ,开发者可通过 catch 来进行捕获 。
wx.onUnhandledRejection 可以监听未处理的 Promise 拒绝事件 。
代码示例
// callback 形式调用 wx.chooseImage({ success(res) { console.log(res:, res) } }) // promise 形式调用 wx.chooseImage().then(res => console.log(res: , res))视图层 View
框架的视图层由 WXML 与 WXSS 编写 ,由组件来进行展示 。
将逻辑层的数据反映成视图 ,同时将视图层的事件发送给逻辑层。
WXML(WeiXin Markup language) 用于描述页面的结构 。
WXS(WeiXin Script) 是小程序的一套脚本语言 ,结合 WXML ,可以构建出页面的结构 。
WXSS(WeiXin Style Sheet) 用于描述页面的样式。
组件(Component)是视图的基本组成单元 。
WXML
WXML(WeiXin Markup Language)是框架设计的一套标签语言 ,结合基础组件 、事件系统 ,可以构建出页面的结构 。
要完整了解 WXML 语法 ,请参考WXML 语法参考 。
用以下一些简单的例子来看看 WXML 具有什么能力:
数据绑定
<!--wxml--> <view> {{message}} </view> // page.js Page({ data: { message: Hello MINA! } })列表渲染
<!--wxml--> <view wx:for="{{array}}"> {{item}} </view> // page.js Page({ data: { array: [1, 2, 3, 4, 5] } })条件渲染
<!--wxml--> <view wx:if="{{view == WEBVIEW}}"> WEBVIEW </view> <view wx:elif="{{view == APP}}"> APP </view> <view wx:else="{{view == MINA}}"> MINA </view> // page.js Page({ data: { view: MINA } })模板
<!--wxml--> <template name="staffName"> <view> FirstName: {{firstName}}, LastName: {{lastName}} </view> </template> <template is="staffName" data="{{...staffA}}"></template> <template is="staffName" data="{{...staffB}}"></template> <template is="staffName" data="{{...staffC}}"></template> // page.js Page({ data: { staffA: {firstName: Hulk, lastName: Hu}, staffB: {firstName: Shang, lastName: You}, staffC: {firstName: Gideon, lastName: Lin} } })具体的能力以及使用方式在以下章节查看:
数据绑定 、列表渲染 、条件渲染、模板 、引用
WXSS
WXSS (WeiXin Style Sheets)是一套样式语言 ,用于描述 WXML 的组件样式 。
WXSS 用来决定 WXML 的组件应该怎么显示 。
为了适应广大的前端开发者 ,WXSS 具有 CSS 大部分特性 。同时为了更适合开发微信小程序,WXSS 对 CSS 进行了扩充以及修改 。
与 CSS 相比 ,WXSS 扩展的特性有:
尺寸单位
样式导入
尺寸单位
rpx(responsive pixel): 可以根据屏幕宽度进行自适应 。规定屏幕宽为750rpx 。如在 iPhone6 上 ,屏幕宽度为375px,共有750个物理像素 ,则750rpx = 375px = 750物理像素 ,1rpx = 0.5px = 1物理像素 。
设备 rpx换算px (屏幕宽度/750) px换算rpx (750/屏幕宽度) iPhone5 1rpx = 0.42px 1px = 2.34rpx iPhone6 1rpx = 0.5px 1px = 2rpx iPhone6 Plus 1rpx = 0.552px 1px = 1.81rpx建议: 开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准 。
注意: 在较小的屏幕上不可避免的会有一些毛刺 ,请在开发时尽量避免这种情况 。
样式导入
使用@import语句可以导入外联样式表 ,@import后跟需要导入的外联样式表的相对路径 ,用;表示语句结束。
示例代码:
/** common.wxss **/ .small-p { padding:5px; } /** app.wxss **/ @import "common.wxss"; .middle-p { padding:15px; }内联样式
框架组件上支持使用 style 、class 属性来控制组件的样式 。
style:静态的样式统一写到 class 中 。style 接收动态的样式 ,在运行时会进行解析 ,请尽量避免将静态的样式写进 style 中 ,以免影响渲染速度。
<view style="color:{{color}};" />class:用于指定样式规则 ,其属性值是样式规则中类选择器名(样式类名)的集合 ,样式类名不需要带上. ,样式类名之间用空格分隔 。
<view class="normal_view" />选择器
目前支持的选择器有:
选择器 样例 样例描述 .class .intro 选择所有拥有 class="intro" 的组件 #id #firstname 选择拥有 id="firstname" 的组件 element view 选择所有 view 组件 element, element view, checkbox 选择所有文档的 view 组件和所有的 checkbox 组件 ::after view::after 在 view 组件后边插入内容 ::before view::before 在 view 组件前边插入内容全局样式与局部样式
定义在 app.wxss 中的样式为全局样式 ,作用于每一个页面 。在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面 ,并会覆盖 app.wxss 中相同的选择器 。
WXS
WXS(WeiXin Script)是小程序的一套脚本语言 ,结合 WXML,可以构建出页面的结构 。
示例
新建一个wxs文件
var toDecimal2 = function (x) { var f = parseFloat(x); if (isNaN(f)) { return 0.00 } var f = Math.round(x * 100) / 100; var s = f.toString(); var rs = s.indexOf(.); if (rs < 0) { rs = s.length; s += .; } while (s.length <= rs + 2) { s += 0; } return s; } //module.exports = toDecimal2 module.exports = { toDecimal2:toDecimal2 }在wxml中使用
<!--pages/c/c.wxml--> <wxs src="../../wxs/PageUtils.wxs" module="PageUtils"></wxs> <wxs module="m1"> var msg = "hello world"; module.exports.message = msg; </wxs> <view> <text>pages/c/c.wxml,</text> <text>{{m1.message}}</text> <view> <text>{{PageUtils.toDecimal2(123.453)}}</text> </view> <view> <button type="primary" bindtap="jump">跳转到D页面</button> </view> </view>注意事项
WXS 不依赖于运行时的基础库版本 ,可以在所有版本的小程序中运行 。
WXS 与 JavaScript 是不同的语言 ,有自己的语法 ,并不和 JavaScript 一致 。
WXS 的运行环境和其他 JavaScript 代码是隔离的 ,WXS 中不能调用其他 JavaScript 文件中定义的函数 ,也不能调用小程序提供的API 。
WXS 函数不能作为组件的事件回调 。
由于运行环境的差异 ,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍 。在 android 设备上二者运行效率无差异 。
以下是一些使用 WXS 的简单示例 ,要完整了解 WXS 语法 ,请参考WXS 语法参考 。
页面渲染
<!--wxml--> <wxs module="m1"> var msg = "hello world"; module.exports.message = msg; </wxs> <view> {{m1.message}} </view>页面输出:
hello world数据处理
// page.js Page({ data: { array: [1, 2, 3, 4, 5, 1, 2, 3, 4] } }) <!--wxml--> <!-- 下面的 getMax 函数 ,接受一个数组 ,且返回数组中最大的元素的值 --> <wxs module="m1"> var getMax = function(array) { var max = undefined; for (var i = 0; i < array.length; ++i) { max = max === undefined ? array[i] : (max >= array[i] ? max : array[i]); } return max; } module.exports.getMax = getMax; </wxs> <!-- 调用 wxs 里面的 getMax 函数 ,参数为 page.js 里面的 array --> <view> {{m1.getMax(array)}} </view>页面输出:
5事件
什么是事件
事件是视图层到逻辑层的通讯方式 。
事件可以将用户的行为反馈到逻辑层进行处理。
事件可以绑定在组件上 ,当达到触发事件,就会执行逻辑层中对应的事件处理函数 。
事件对象可以携带额外信息 ,如 id, dataset, touches 。
事件的使用方式
Page({ tapName: function(event) { console.log(event) } })在组件中绑定一个事件处理函数。
如bindtap ,当用户点击该组件的时候会在该页面对应的 Page 中找到相应的事件处理函数 。
<view id="tapTest" data-hi="Weixin" bindtap="tapName"> Click me! </view>在相应的 Page 定义中写上相应的事件处理函数,参数是event 。
Page({ tapName: function(event) { console.log(event) } })可以看到 log 出来的信息大致如下:
{ "type":"tap", "timeStamp":895, "target": { "id": "tapTest", "dataset": { "hi":"Weixin" } }, "currentTarget": { "id": "tapTest", "dataset": { "hi":"Weixin" } }, "detail": { "x":53, "y":14 }, "touches":[{ "identifier":0, "pageX":53, "pageY":14, "clientX":53, "clientY":14 }], "changedTouches":[{ "identifier":0, "pageX":53, "pageY":14, "clientX":53, "clientY":14 }] }使用 WXS 函数响应事件
基础库 2.4.4 开始支持 ,低版本需做兼容处理 。
从基础库版本2.4.4开始 ,支持使用 WXS 函数绑定事件 ,WXS函数接受2个参数 ,第一个是event ,在原有的 event 的基础上加了event.instance对象 ,第二个参数是ownerInstance ,和event.instance一样是一个ComponentDescriptor对象 。具体使用如下:
在组件中绑定和注册事件处理的 WXS 函数 。
<wxs module="wxs" src="./test.wxs"></wxs> <view id="tapTest" data-hi="Weixin" bindtap="{{wxs.tapName}}"> Click me! </view> **注:绑定的 WXS 函数必须用{{}}括起来** test.wxs文件实现 tapName 函数 function tapName(event, ownerInstance) { console.log(tap Weixin, JSON.stringify(event)) } module.exports = { tapName: tapName }ownerInstance包含了一些方法 ,可以设置组件的样式和class ,具体包含的方法以及为什么要用 WXS 函数响应事件 ,请点击查看详情 。
事件详解
事件分类
事件分为冒泡事件和非冒泡事件:
冒泡事件:当一个组件上的事件被触发后 ,该事件会向父节点传递 。
非冒泡事件:当一个组件上的事件被触发后 ,该事件不会向父节点传递 。
WXML的冒泡事件列表:
类型 触发条件 最低版本 touchstart 手指触摸动作开始 touchmove 手指触摸后移动 touchcancel 手指触摸动作被打断,如来电提醒 ,弹窗 touchend 手指触摸动作结束 tap 手指触摸后马上离开 longpress 手指触摸后 ,超过350ms再离开,如果指定了事件回调函数并触发了这个事件 ,tap事件将不被触发 1.5.0 longtap 手指触摸后 ,超过350ms再离开(推荐使用 longpress 事件代替) transitionend 会在 WXSS transition 或 wx.createAnimation 动画结束后触发 animationstart 会在一个 WXSS animation 动画开始时触发 animationiteration 会在一个 WXSS animation 一次迭代结束时触发 animationend 会在一个 WXSS animation 动画完成时触发 touchforcechange 在支持 3D Touch 的 iPhone 设备 ,重按时会触发 1.9.90注:除上表之外的其他组件自定义事件如无特殊声明都是非冒泡事件 ,如 form 的submit事件 ,input 的input事件 ,scroll-view 的scroll事件 ,(详见各个组件)
普通事件绑定
事件绑定的写法类似于组件的属性 ,如:
<view bindtap="handleTap"> Click here! </view>如果用户点击这个 view ,则页面的 handleTap 会被调用 。
事件绑定函数可以是一个数据绑定 ,如:
<view bindtap="{{ handlerName }}"> Click here! </view>此时 ,页面的 this.data.handlerName 必须是一个字符串 ,指定事件处理函数名;如果它是个空字符串,则这个绑定会失效(可以利用这个特性来暂时禁用一些事件) 。
自基础库版本 1.5.0 起 ,在大多数组件和自定义组件中 , bind 后可以紧跟一个冒号,其含义不变 ,如 bind:tap 。基础库版本 2.8.1 起 ,在所有组件中开始提供这个支持 。
绑定并阻止事件冒泡
除 bind 外 ,也可以用 catch 来绑定事件。与 bind 不同 , catch 会阻止事件向上冒泡 。
例如在下边这个例子中 ,点击 inner view 会先后调用handleTap3和handleTap2(因为 tap 事件会冒泡到 middle view ,而 middle view 阻止了 tap 事件冒泡 ,不再向父节点传递) ,点击 middle view 会触发handleTap2 ,点击 outer view 会触发handleTap1 。
<view id="outer" bindtap="handleTap1"> outer view <view id="middle" catchtap="handleTap2"> middle view <view id="inner" bindtap="handleTap3"> inner view </view> </view> </view>互斥事件绑定
自基础库版本 2.8.2 起 ,除 bind 和 catch 外 ,还可以使用 mut-bind 来绑定事件。一个 mut-bind 触发后 ,如果事件冒泡到其他节点上,其他节点上的 mut-bind 绑定函数不会被触发 ,但 bind 绑定函数和 catch 绑定函数依旧会被触发 。
换而言之 ,所有 mut-bind 是“互斥 ”的,只会有其中一个绑定函数被触发 。同时 ,它完全不影响 bind 和 catch 的绑定效果 。
例如在下边这个例子中 ,点击 inner view 会先后调用 handleTap3 和 handleTap2 ,点击 middle view 会调用 handleTap2 和 handleTap1 。
<view id="outer" mut-bind:tap="handleTap1"> outer view <view id="middle" bindtap="handleTap2"> middle view <view id="inner" mut-bind:tap="handleTap3"> inner view </view> </view> </view>事件的捕获阶段
自基础库版本 1.5.0 起 ,触摸类事件支持捕获阶段 。捕获阶段位于冒泡阶段之前 ,且在捕获阶段中 ,事件到达节点的顺序与冒泡阶段恰好相反 。需要在捕获阶段监听事件时 ,可以采用capture-bind、capture-catch关键字 ,后者将中断捕获阶段和取消冒泡阶段 。
在下面的代码中 ,点击 inner view 会先后调用handleTap2 、handleTap4 、handleTap3 、handleTap1 。
<view id="outer" bind:touchstart="handleTap1" capture-bind:touchstart="handleTap2"> outer view <view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4"> inner view </view> </view>如果将上面代码中的第一个capture-bind改为capture-catch ,将只触发handleTap2 。
<view id="outer" bind:touchstart="handleTap1" capture-catch:touchstart="handleTap2"> outer view <view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4"> inner view </view> </view>事件对象
如无特殊说明 ,当组件触发事件时 ,逻辑层绑定该事件的处理函数会收到一个事件对象 。
BaseEvent 基础事件对象属性列表:
属性 类型 说明 基础库版本 type String 事件类型 timeStamp Integer 事件生成时的时间戳 target Object 触发事件的组件的一些属性值集合 currentTarget Object 当前组件的一些属性值集合 mark Object 事件标记数据 2.7.1CustomEvent 自定义事件对象属性列表(继承 BaseEvent):
属性 类型 说明 detail Object 额外的信息TouchEvent 触摸事件对象属性列表(继承 BaseEvent):
属性 类型 说明 touches Array 触摸事件,当前停留在屏幕中的触摸点信息的数组 changedTouches Array 触摸事件 ,当前变化的触摸点信息的数组特殊事件: canvas 中的触摸事件不可冒泡 ,所以没有 currentTarget 。
type
代表事件的类型 。
timeStamp
页面打开到触发事件所经过的毫秒数。
target
触发事件的源组件 。
属性 类型 说明 id String 事件源组件的id dataset Object 事件源组件上由data-开头的自定义属性组成的集合currentTarget
事件绑定的当前组件 。
属性 类型 说明 id String 当前组件的id dataset Object 当前组件上由data-开头的自定义属性组成的集合说明: target 和 currentTarget 可以参考上例中,点击 inner view 时 ,handleTap3 收到的事件对象 target 和 currentTarget 都是 inner ,而 handleTap2 收到的事件对象 target 就是 inner ,currentTarget 就是 middle。
dataset
在组件节点中可以附加一些自定义数据 。这样 ,在事件中可以获取这些自定义的节点数据 ,用于事件的逻辑处理 。
在 WXML 中 ,这些自定义数据以 data- 开头 ,多个单词由连字符 - 连接 。这种写法中 ,连字符写法会转换成驼峰写法 ,而大写字符会自动转成小写字符 。如:
data-element-type ,最终会呈现为 event.currentTarget.dataset.elementType ;
data-elementType ,最终会呈现为 event.currentTarget.dataset.elementtype 。
示例:
<view data-alpha-beta="1" data-alphaBeta="2" bindtap="bindViewTap"> DataSet Test </view> Page({ bindViewTap:function(event){ event.currentTarget.dataset.alphaBeta === 1 // - 会转为驼峰写法 event.currentTarget.dataset.alphabeta === 2 // 大写会转为小写 } })mark
在基础库版本 2.7.1 以上 ,可以使用 mark 来识别具体触发事件的 target 节点 。此外, mark 还可以用于承载一些自定义数据(类似于 dataset ) 。
当事件触发时 ,事件冒泡路径上所有的 mark 会被合并 ,并返回给事件回调函数 。(即使事件不是冒泡事件,也会 mark 。)
代码示例:
在开发者工具中预览效果
<view mark:myMark="last" bindtap="bindViewTap"> <button mark:anotherMark="leaf" bindtap="bindButtonTap">按钮</button> </view>在上述 WXML 中 ,如果按钮被点击 ,将触发 bindViewTap 和 bindButtonTap 两个事件 ,事件携带的 event.mark 将包含 myMark 和 anotherMark 两项 。
Page({ bindViewTap: function(e) { e.mark.myMark === "last" // true e.mark.anotherMark === "leaf" // true } })mark 和 dataset 很相似 ,主要区别在于: mark 会包含从触发事件的节点到根节点上所有的 mark: 属性值;而 dataset 仅包含一个节点的 data- 属性值 。
细节注意事项:
如果存在同名的 mark ,父节点的 mark 会被子节点覆盖 。
在自定义组件中接收事件时 , mark 不包含自定义组件外的节点的 mark 。
不同于 dataset ,节点的 mark 不会做连字符和大小写转换 。
touches
touches 是一个数组 ,每个元素为一个 Touch 对象(canvas 触摸事件中携带的 touches 是 CanvasTouch 数组) 。 表示当前停留在屏幕上的触摸点。
Touch 对象
属性 类型 说明 identifier Number 触摸点的标识符 pageX, pageY Number 距离文档左上角的距离 ,文档的左上角为原点 ,横向为 X 轴 ,纵向为 Y 轴 clientX, clientY Number 距离页面可显示区域(屏幕除去导航条)左上角距离 ,横向为 X 轴,纵向为 Y 轴CanvasTouch 对象
属性 类型 说明 特殊说明 identifier Number 触摸点的标识符 x, y Number 距离 Canvas 左上角的距离 ,Canvas 的左上角为原点 ,横向为 X 轴,纵向为 Y 轴changedTouches
changedTouches 数据格式同 touches 。 表示有变化的触摸点 ,如从无变有(touchstart) ,位置变化(touchmove) ,从有变无(touchend 、touchcancel) 。
detail
自定义事件所携带的数据 ,如表单组件的提交事件会携带用户的输入 ,媒体的错误事件会携带错误信息 ,详见组件定义中各个事件的定义 。
点击事件的detail 带有的 x, y 同 pageX, pageY 代表距离文档左上角的距离 。
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!