• 小程序05 深入小程序框架


    MINA框架

    概述

    之前介绍的WXML、WXSS、JS、WXS都是运行在MINA框架上。

    MINA的核心是一个响应的数据绑定系统。整个系统分为两块:视图层(View) 和 逻辑层(App Service)。MINA可以让数据与视图保持同步非常简单。当做数据修改的时候,只需要在逻辑层修改数据,视图层就会做相应的更新。

    框架实现

    框架原理图如下:

     

    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技术,加快了页面的渲染效率。

    运行机制

    启动

    分为热启动和冷启动。

    • 冷启动:用户第一次访问小程序,需要到服务器加载小程序代码包。或者用户访问已经被微信主动销毁的小程序。
    • 微信销毁小程序时机:小程序进入后台后5分钟;或者小程序在连续两次间隔5秒发生告警。
    • 热启动:假如用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时无需重新启动,只需将后台态的小程序切换到前台,这个过程就是热启动。
    • 小程序的更新机制:小程序冷启动时如果发现有新版本,将会异步下载新版本的代码包,并同时用客户端本地的包进行启动,即新版本的小程序需要等下一次冷启动才会应用上。

    加载

    小程序启动的时候会从CDN服务器上加载小程序代码包,并缓存到微信后台,下载完成后启动小程序。如果本地已经缓存小程序代码包,每次启动小程序,微信会从CDN上查询是否有新版本的代码包,如果有,则在后台下载,下次启动的时候启用新版小程序。

    小程序通过AJAX向应用服务器发起请求,应用服务器返回JSON格式的数据。

    生命周期

    应用生命周期

    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

    注意:

    •  App() 必须在 app.js 中注册,且不能注册多个。
    • 不要在定义于 App() 内的函数中调用 getApp() ,使用 this 就可以拿到 app 实例。
    • 不要在 onLaunch 的时候调用 getCurrentPage(),此时 page 还没有生成。
    • 通过 getApp() 获取实例之后,不要私自调用生命周期函数。

    页面生命周期

    Page()函数用来注册一个页面。接受一个 object 参数,其指定页面的初始数据、生命周期函数、事件处理函数等。

    object 参数说明:

     

    • 小程序注册完成后,加载页面,触发onLoad方法。
    • 面载入后触发onShow方法,显示页面。
    • 首次显示页面会触发onReady方法,渲染页面元素和样式,一个页面只会调用一次。
    • 当小程序后台运行或跳转到其他页面时,触发onHide方法。
    • 当小程序有后台进入到前台运行或重新进入页面时,触发onShow方法。
    • 当使用重定向方法wx.redirectTo(OBJECT)或关闭当前页返回上一页wx.navigateBack(),触发onUnload。

    注意:

    onLoad: 页面加载。

    • 一个页面只会调用一次。
    • 参数可以获取wx.navigateTo和wx.redirectTo及<navigator/>中的 query。

    onShow: 页面显示

    • 每次打开页面都会调用一次。

    onReady: 页面初次渲染完成

    • 一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。
    • 对界面的设置如wx.setNavigationBarTitle请在onReady之后设置。详见生命周期。

    onHide: 页面隐藏

    • 当navigateTo或底部tab切换时调用。

    onUnload: 页面卸载

    • 当redirectTo或navigateBack的时候调用。

    AppService线程和View线程的交互

     

    由上图可知,小程序由两大线程组成:负责界面的视图线程(view thread)和负责数据、服务处理的服务线程(appservice thread),两者协同工作,完成小程序页面生命周期的调用。

    视图线程有四大状态:

    1. 初始化状态:初始化视图线程所需要的工作,初始化完成后向 “服务线程”发送初始化完成信号,然后进入等待状态,等待服务线程提供初始化数据。
    2. 首次渲染状态:当收到服务线程提供的初始化数据后(json和js中的data数据),渲染小程序界面,渲染完毕后,发送“首次渲染完成信号”给服务线程,并将页面展示给用户。
    3. 持续渲染状态:此时界面线程继续一直等待“服务线程”通过this.setdata()函数发送来的界面数据,只要收到就重新局部渲染,也因此只要更新数据并发送信号,界面就自动更新。
    4. 结束状态:页面被回收或者销毁、应用被系统回收、销毁时触发。

    服务线程五大状态:

    1. 初始化状态:此阶段仅启动服务线程所需的基本功能,比如信号发送模块。系统的初始化工作完毕,就调用自定义的onload和onshow,然后等待视图线程的“视图线程初始化完成”号。onload是只会首次渲染的时候执行一次,onshow是每次界面切换都会执行,简单理解,这就是唯一差别。
    2. 等待激活状态:接收到“视图线程初始化完成”信号后,将初始化数据发送给“视图线程”,等待视图线程完成初次渲染。
    3. 激活状态:收到视图线程发送来的“首次渲染完成”信号后,就进入激活状态既程序的正常运行状态,并调用自定义的onReady()函数。此状态下就可以通过 this.setData 函数发送界面数据给界面线程进行局部渲染,更新页面。
    4. 后台运行状态:如果界面进入后台,服务线程就进入后台运行状态,从目前的官方解读来说,这个状态挺奇怪的,和激活状态是相同的,也可以通过setdata函数更新界面的。毕竟小程序的框架刚推出,应该后续会有很大不同吧。
    5. 结束状态:页面被回收或者销毁、应用被系统回收、销毁时触发。

    应用的生命周期对页面生命周期的影响

     

    • 小程序初始化完成后,页面首次加载触发onLoad,只会触发一次。
    • 当小程序进入到后台,先执行页面onHide方法再执行应用onHide方法。
    • 当小程序从后台进入到前台,先执行应用onShow方法再执行页面onShow方法。

     

    路由

    在小程序中所有页面的路由全部由框架进行管理。

    路由方式

     

    对于路由的触发方式以及页面生命周期函数如下:

    注意:

    • navigateTo, redirectTo 只能打开非 tabBar 页面。
    • switchTab 只能打开 tabBar 页面。
    • reLaunch 可以打开任意页面。
    • 页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
    • 调用页面路由带的参数可以在目标页面的onLoad中获取。

    Tab 切换对应的生命周期

    (以 A、B 页面为 Tabbar 页面,C 是从 A 页面打开的页面,D 页面是从 C 页面打开的页面为例):

     

    事件

    定义

    • 事件是视图层到逻辑层的通讯方式。
    • 事件可以将用户的行为反馈到逻辑层进行处理。
    • 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。
    • 事件对象可以携带额外信息,如 id, dataset, touches。

    事件示例

    视图代码:

    <!--index.wxml-->

    <view>

      <view class='btn' bindtap='clickme'>点击我

      </view>

    </view>

    样式代码:

    /**index.wxss**/

    .btn{

      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;

      80%;

      height: 200px;

      margin: 100px auto;

      text-align: center;

    }

     

    #middle{

      border: 1px white solid;

      background-color: white;

      80%;

      height: 120px;

      margin: 20px auto;

    }

     

    #inner{

      border: 1px yellow solid;

      background-color: yellow;

      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,测试结果:

     

     分别点击C3、C2、C1,测试结果:

    注意:

    1. bindtap不会阻止事件的冒泡。
    2. capture-catch可以阻止冒泡。示例代码如下:

    <!--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容器:

     



    本博客文章未经许可,禁止转载和商业用途!

    如有疑问,请联系: 2083967667@qq.com


  • 相关阅读:
    Ubuntu下VSFTPD(五)(匿名FTP设置方法)
    Ubuntu下VSFTPD(六)(常见FTP命令及其功能) (
    ubuntu13.04装配oracle11gR2
    oracle之报错:ORA-00054: 资源正忙,要求指定 NOWAIT_数据库的几种锁
    oracle建索引的可选项
    Oracle自定义函数
    C# WinForm开发系列
    为C#自定义控件添加自定义事件
    python 爬虫抓取心得
    C# 正则表达式学习
  • 原文地址:https://www.cnblogs.com/rask/p/9667866.html
Copyright © 2020-2023  润新知