微信小程序:开发入门及案例详解
上QQ阅读APP看书,第一时间看更新

2.4.2 页面逻辑文件(JavaScript)

页面逻辑文件主要功能有:设置初始化数据,注册当前页面生命周期函数,注册事件处理函数等。小程序的逻辑层文件是JavaScript文件,所有的逻辑文件,包括app.js,最终将会打包成一个js文件,在小程序启动时运行,直到小程序销毁,类似于ServiceWorker,所以逻辑层也称为App Service。

在小程序中,每个逻辑文件有独立的作用域,并具备模块化能力。由于JavaScript逻辑文件是运行在纯JavaScript引擎中而并非运行在浏览器中,一些浏览器提供的特有对象,如document、window等,在小程序中都无法使用,同理,一些基于document、window的框架如:jQuery、Zepto都不能在小程序中使用,同时我们不能通过操作DOM改变页面,这时需要我们将面向DOM操作的编程思路转化为数据绑定和事件响应。

1.注册页面

在页面逻辑文件中需要通过Page()函数注册页面,指定页面的初始数据、生命周期函数、事件处理函数等,参数为一个Object对象,其属性如下:

□data:页面的初始数据,数据格式必须是可转成JSON格式的对象类型。当页面第一次渲染时,data会以JSON的形式由逻辑层传至渲染层,渲染层可以通过WXML对数据进行绑定。

□onLoad:生命周期函数,页面加载时触发。一个页面只会调用一次,接受页面参数,可以获取wx.navigateTo、wx.redirectTo以及<navigator/>中的query参数。

□onShow:生命周期函数,页面显示时触发。每次打开页面都会调用一次。

□onReady:生命周期函数,页面初次渲染完成时触发。一个页面生命周期中只会调用一次,代表当前页面已经准备妥当,可以和视图层进行交互。一些对界面的设置,操作需要在页面准备妥当后调用,如wx.setNavigationBarTitle需要在onReady之后设置,详细可以参考后面的“页面生命周期”小节。

□onHide:生命周期函数,页面隐藏时触发。

□onUnload:生命周期函数,页面卸载时触发。

□onPullDownRefresh:页面相关时间处理函数,用户下拉时触发。使用时需要将app. json配置中window的enablePullDownRefresh属性设置为true。当处理完数据刷新后,可以调用wx.stopPullDownRefresh方法停止当前页面的下拉刷新。

□onReachBottom:页面上拉触底事件的处理函数。

□其他:开发者可以添加任意的函数或数据到Object参数中,可以用this访问这些函数和数据。

示例代码如代码清单2-2所示:

代码清单2-2 页面逻辑文件

    // 获取app实例
    var app = getApp();
    Page( {
      data : { // 页面初始化数据
        count : 0
      },
      onLoad : function() {
        // 页面加载时执行
      },
      onShow : function() {
        // 页面打开时执行
        console.log( app.globalData );
      },
      onReady : function() {
        // 页面初次渲染完成执行,一个页面只会调用一次
      },
      onHide : function() {
        // 页面隐藏时执行
      },
      onUnload : function() {
        // 页面卸载时执行
      },
      onPullDownRefresh : function() {
        // 下拉刷新时执行
      },
      onReachBottom : function() {
        // 下拉触底时执行
      },
      // 自定义函数,可与渲染层中的组件进行事件绑定
      countClick : function() {
         // 触发视图层重新渲染
         this.setData( {
          count : this.data.count + 1
         } );
      },
      // 自定义数据
      customData : {
         name : ’微信’
      }
    } );

页面的生命周期函数比小程序的生命周期函数略微复杂一点,弄懂其执行顺序能避免在不恰当的生命周期函数中调用还未创建的对象或方法,小程序框架以栈的形式维护了当前的所有页面,当发生路由切换时,页面栈和生命周期函数的关系如下:

□小程序初始化:默认页面入栈,依次触发默认页面onLoad、onShow、onReady方法。

□打开新页面:新页面入栈,依次触发新页面onLoad、onShow、onReady方法。

□页面重定向:当前页面出栈并卸载,触发当前页面onUnload方法,新页面入栈,触发新页面onLoad、onShow、onReady方法。

□页面返回:页面不断出栈并卸载,触发当前弹出页面onUnload方法,直到返回目标页面,新页面入栈,触发新页面onShow方法。

□Tab切换:当前页面出栈但不卸载,仅触发onHide方法,新页面入栈,如果当前页面是新加载的,触发onLoad、onShow、onReady方法,如果当前页面已加载过,仅触发onShow方法。

□程序从前台到后台:触发当前页面onHide方法,触发App onHide方法。

□程序从后台到前台:触发小程序onShow方法,触发页面onShow方法。

整体来说,如果页面在生命周期中,只会触发onShow和onLoad方法,只有加载和卸载时才会触发onLoad、onReady和onUnload方法,而触发页面卸载只有页面返回和页面重定向两种操作。页面生命周期函数的执行顺序不用死记硬背,开发过程中可以开启app. json中的debug模式,路由切换时,小程序、页面的生命周期函数执行顺序都会在控制台以info形式输出,在后面小节中我们将对页面生命周期作简单介绍。

2.获取当前页面栈

有注册就有获取,getCurrentPages()函数便是用于获取当前页面栈的实例,页面栈以数组形式按栈顺序给出,第一个元素为首页,最后一个元素为当前页面。不要尝试修改页面栈,这会导致路由以及页面状态错误。

示例代码如下:

    /* 获取页面栈 */
    var pages = getCurrentPages();
    /* 获取当前页面对象 */
    var currentPage = pages[pages.length - 1];

3.事件处理函数

页面对象中注册的函数可以和视图层中的组件进行绑定,当达到触发条件时,就会执行Page中定义的相应事件,这类自定义函数统称为事件处理函数。小程序中组件的事件分为通用事件和特殊事件,事件类型请参考后面2.4.3节中“事件”小节。

示例代码如下:

    <view bindtap= "myevent ">点击执行逻辑层事件</view>
    Page( {
      myevent : function() {
        console.log( ’点击了view' );
      }
    } );

4.触发视图层渲染

页面首次加载时,框架会结合初始化数据渲染页面,在逻辑层中则需主动调用Page.

prototype.setData()方法,而不能直接修改Page的data值,这样不仅无法触发视图层渲染,还会造成数据不一致。当Page.prototype.setData()被调用时,会将数据从逻辑层发送到视图层触发视图层重绘,同时会修改Page的data值。setData()接受一个Object对象参数,方法会自动将this.data中的key对应的值变成Object参数中key对应的值。当Object参数key对应的值和this.data中key对应的值一致时,将不会触发视图层渲染。在项目中我们一定要保证视图层和逻辑层的数据一致。

Object参数的key值非常灵活,可以按数据路径的形式给出,如array[5].info、obj.key.subkey,并且这样使用时,不需要在this.data中预先定义。

示例代码如下:

    <view>{{text}}</view>
    <button bindtap="changeText">修改普通数据</button>
    <view>{{object.subObject.objectText}}</view>
    <button bindtap="changeObjectText">修改对象数据</button>
    <view>{{array[0].arrayText}}</view>
    <button bindtap="changeArrayText">修改数组数据</button>
    <view>{{newField.newFieldText}}</view>
    <button bindtap="addNewData">添加新字段</button>
    Page( {
      data : {
        text : 'normal data',
        object : {
          subObject : {
            objectText : 'object data'
          }
        },
        array : [
          { arrayText : 'array data' }
        ]
      },
      changeText : function() {
        this.setData( {
          /* 普通索引 */
          text : 'new normal data'
        } );
      },
      changeObjectText : function() {
        this.setData( {
          /* 按路径索引 */
          'object.subObject.objectText' : 'new object data'
        } );
      },
      changeArrayText : function() {
        this.setData( {
          /* 按路径索引 */
          'array[0].arrayText' : 'new array data'
        } );
      },
      addNewData : function() {
        this.setData( {
          /* 修改一个已绑定,但未在data中定义的数据 */
          'newField.newFieldText' : 'add new data'
        } );
      }
    } );

5.页面生命周期

页面的生命周期整体关系着页面视图层线程和页面逻辑层线程,注册页面时,Object参数中很多属性都是生命周期函数,这些函数的调用和页面生命息息相关,程序视图层线程和逻辑层线程关系如图2-8所示。

图2-8 Page实例的生命周期

如图2-8,线程启动后视图层和逻辑层相互监听,当逻辑层线程触发onLoad、onShow方法后会把初始数据data传送给视图层线程,视图层完成第一次渲染后触发逻辑层onReady方法,代表页面已经准备妥当,之后我们便可通过setData方法主动触发视图层渲染。当页面被调往后台时,触发onHide方法,这时逻辑层线程并没有销毁,我们仍然可以通过代码控制视图层渲染,只是可能不会在界面上表现出来。当页面从后台回到前台时,触发onShow方法,最后当页面销毁时,触发onUnload方法。整体来看onLoad、onReady和onUnload方法在生命周期中只会调用一次,生命周期内显示、隐藏页面都是触发onShow和onHide方法,在路由方式中,只有页面重定向和页面返回会结束当前页面生命周期,当进入一个已加载的页面时只会触发onShow方法,不会触发onLoad和onReady方法。