以前介绍的WXML、WXSS、JS、WXS都是运行在MINA框架上。html
MINA的核心是一个响应的数据绑定系统。整个系统分为两块:视图层(View) 和 逻辑层(App Service)。MINA可让数据与视图保持同步很是简单。当作数据修改的时候,只须要在逻辑层修改数据,视图层就会作相应的更新。json
框架原理图以下:小程序
View视图层:wxml是MINA提供的一套相似html标签的语言以及一系列基础组件。开发者使用wxml文件来搭建页面的基础视图结构,使用wxss文件来控制页面的展示样式。缓存
AppService应用逻辑层:MINA的服务中心,由微信客户端启用异步线程单独加载运行。页面渲染所需的数据、页面交互处理逻辑都在AppService中实现。MINA框架中的AppService使用JavaScript来编写交互逻辑、网络请求、数据处理,但不能使用JavaScript中的DOM操做。小程序中的各个页面能够经过AppService实现数据管理、网络通讯、应用生命周期管理和页面路由。Mananger用于处理事件逻辑和事件处理,API向外提供了应用接口。服务器
MINA框架为页面组件提供了bindtap、bindtouchstart等事件监听相关的属性,来与AppService中的事件处理函数绑定在一块儿,实现也面向AppService层同步用户交互数据。MINA框架同时提供了不少方法将AppService中的数据与页面进行单向绑定,当AppService中的数据变动时,会主动触发对应页面组件的从新渲染。MINA使用virtualdom技术,加快了页面的渲染效率。微信
分为热启动和冷启动。网络
小程序启动的时候会从CDN服务器上加载小程序代码包,并缓存到微信后台,下载完成后启动小程序。若是本地已经缓存小程序代码包,每次启动小程序,微信会从CDN上查询是否有新版本的代码包,若是有,则在后台下载,下次启动的时候启用新版小程序。并发
小程序经过AJAX向应用服务器发起请求,应用服务器返回JSON格式的数据。app
App() 函数用来注册一个小程序。接受一个 object 参数,其指定小程序的生命周期函数等。object参数说明:框架
属性 |
类型 |
描述 |
触发时机 |
onLaunch |
Function |
生命周期函数--监听小程序初始化 |
当小程序初始化完成时,会触发 onLaunch(全局只触发一次) |
onShow |
Function |
生命周期函数--监听小程序显示 |
当小程序启动,或从后台进入前台显示,会触发 onShow |
onHide |
Function |
生命周期函数--监听小程序隐藏 |
当小程序从前台进入后台,会触发 onHide |
onError |
Function |
生命周期函数--监听小程序错误信息 |
当小程序调用API失败时候会调用onError钩子,并传入错误信息。 |
前台、后台定义: 当用户点击左上角关闭,或者按了设备 Home 键离开微信,小程序并无直接销毁,而是进入了后台;当再次进入微信或再次打开小程序,又会从后台进入前台。
示意图:
globalData表示小程序全局数据。
示例代码:
App({ onLaunch: function () { console.log("小程序初始化"); }, onShow: function () { console.log("小程序进入前台"); }, onHide: function () { console.log("小程序进入后台"); }, onError: function (msg) { console.log(msg) }, globalData: '全局数据' }) |
小程序提供了全局的 getApp()函数,能够获取到小程序实例。
示例代码:
// other.js var appInstance = getApp() console.log(appInstance.globalData) // I am global data |
注意:
Page()函数用来注册一个页面。接受一个 object 参数,其指定页面的初始数据、生命周期函数、事件处理函数等。
object 参数说明:
注意:
onLoad: 页面加载。
onShow: 页面显示
onReady: 页面初次渲染完成
onHide: 页面隐藏
onUnload: 页面卸载
由上图可知,小程序由两大线程组成:负责界面的视图线程(view thread)和负责数据、服务处理的服务线程(appservice thread),二者协同工做,完成小程序页面生命周期的调用。
视图线程有四大状态:
服务线程五大状态:
在小程序中全部页面的路由所有由框架进行管理。
对于路由的触发方式以及页面生命周期函数以下:
注意:
(以 A、B 页面为 Tabbar 页面,C 是从 A 页面打开的页面,D 页面是从 C 页面打开的页面为例):
视图代码:
<!--index.wxml--> <view> <view class='btn' bindtap='clickme'>点击我 </view> </view> |
样式代码:
/**index.wxss**/ .btn{ width: 100px; height: 30px; text-align: center; border: 1px solid black; line-height: 30px; margin: 100px auto; } |
逻辑层处理代码:
//index.js Page({ //点击事件处理函数 clickme: function(e) { console.log(e); } }) |
控制台输出:
事件属性说明:
Tap:触发事件类型。
changedTouches:表示有变化的触摸点,如从无变有(touchstart),位置变化(touchmove),从有变无(touchend、touchcancel)。
currentTarget:事件绑定的当前组件。
Target:触发事件的源组件。
detail:自定义事件所携带的数据,如表单组件的提交事件会携带用户的输入,媒体的错误事件会携带错误信息,详见组件定义中各个事件的定义。点击事件的detail 带有的 x, y 同 pageX, pageY 表明距离文档左上角的距离。
和JavaScript的事件模型相似
tap表示按压屏幕小于350ms。
longpress:按压时间超过350ms的事件操做,不会再触发tap操做。(长按操做推荐)
longtap:触发以后会继续触发tap操做。
样式文件:
/* pages/index/index.wxss */ #outter{ border: 1px red solid; background-color: red; width: 80%; height: 200px; margin: 100px auto; text-align: center; }
#middle{ border: 1px white solid; background-color: white; width: 80%; height: 120px; margin: 20px auto; }
#inner{ border: 1px yellow solid; background-color: yellow; width: 80%; height: 50px; margin: 10px auto; } |
事件回调函数定义:
// pages/index/index.js Page({ click1() { console.log("冒泡:点击了C1"); }, click2() { console.log("冒泡:点击了C2"); }, click3() { console.log("冒泡:点击了C3"); }, click11() { console.log("捕获:点击了C1"); }, click22() { console.log("捕获:点击了C2"); }, click33() { console.log("捕获:点击了C3"); } }) |
视图层代码:
<!--pages/index/index.wxml--> <view id="outter" bindtap='click1' capture-bind:tap="click11"> 外层容器C1 <view id="middle" bindtap='click2' capture-bind:tap="click22"> 中间层容器C2 <view id="inner" bindtap='click3' capture-bind:tap="click33"> 内层容器C3 </view> </view> </view> |
点击C1,测试结果:
分别点击C三、C二、C1,测试结果:
注意:
<!--pages/index/index.wxml--> <view id="outter" bindtap='click1' capture-bind:tap="click11"> 外层容器C1 <view id="middle" bindtap='click2' capture-bind:tap="click22"> 中间层容器C2 <view id="inner" bindtap='click3' capture-catch:tap="click33"> 内层容器C3 </view> </view> </view> |
测试效果,点击C3容器: