Menu
小程序资讯
小程序资讯
微信小程序开发进阶篇:生命周期、数据绑定与模块化
时间:2016-10-19 11:27:00
一:生命周期

准备写一个小系列,帮大家梳理一下微信小程序整体的技术架构。 尽量做到用最短的篇幅说明问题,帮助大家快速了解这个平台。 这次就先说说小程序的生命周期。

关于生命周期,这在很多开发生态周都会有,比如原生的 iOS 和 Android 开发中都有类似的概念。

这次咱们就详细了解一下小程序的生命周期。以及两个核心概念 —— App 和 Page。

App()

App 函数是整个小程序的入口, 这在我们上篇文章中已经介绍了, 咱们再把代码贴出来回顾一遍:

App({

  onLaunch: function () {

    //调用API从本地缓存中获取数据

    var logs = wx.getStorageSync('logs') || []

    logs.unshift(Date.now())

    wx.setStorageSync('logs', logs)

  },  

  getUserInfo:function(cb){

    var that = this

    if(this.globalData.userInfo){

      typeof cb == "function" && cb(this.globalData.userInfo)

    }else{

      //调用登录接口

      wx.login({

        success: function () {

          wx.getUserInfo({

            success: function (res) {

              that.globalData.userInfo = res.userInfo

              typeof cb == "function" && cb(that.globalData.userInfo)

            }

          })

        }

      })

    }

  },

  globalData:{

    userInfo:null

  }

})

大体上就是这样了, 微信开发工具的默认项目中定义了 onLaunch 方法, 它就是一个生命周期方法。 除了这个方法之外, 还有另外两个生命周期方法, 这里给大家列出:

onLaunch: 小程序初始化完成。
onShow: 小程序显示,初始化完成后会调用, 从后台切换进来也会调用。
onHide: 小程序隐藏,用户在微信中点后退按钮算隐藏, 用户按 Home 键切回桌面也算隐藏, 这时 onHide 方法都会被调用。

这就是 App 目前开放的所有的生命周期方法了。根据你的小程序业务逻辑,使用这些生命周期方法即可。

getApp()

微信还给我们提供了 getApp 函数, 这是一个全局函数, 在任何地方调用这个函数都可以得到 App 的实例,供我们使用。 这样我们在需要使用 App 对象相关属性的时候,就可以引用到它了。

Page

Page 是小程序中另外一个重要的对象, 它表示小程序的每一个单独的页面。 它也包含生命周期。 它的方法如下:

data: 表示页面的数据, 用于前端 UI 显示数据。
onLoad: 页面加载完成。
onReady: 页面渲染完成。
onShow: 页面显示。
onHide: 页面隐藏。
onUnload: 页面卸载。

Page 的基本结构如下:

Page({

  data: {

    message: "Hello world."

  },

  onLoad: function(options) {

    // Do some initialize when page load.

  },

  onReady: function() {

    // Do something when page ready.

  },

  onShow: function() {

    // Do something when page show.

  },

  onHide: function() {

    // Do something when page hide.

  },

  onUnload: function() {

    // Do something when page close.

  }

})

当前端页面需要显示数据的时候, 可以这样:

<!-- 

<view>{{message}}</view> 

-->

这里面的 message 就是引用的 Page 对象中,我们定义在 data 属性中的 key 所对应的内容了。 这样 Page 以及它的数据如何与前端显示绑定起来的流程咱们就明白了。

接下来, 我们怎么处理前端 UI 上面的用户操作事件呢? 比如用户点击, 我们可以使用 bindtap 属性:

<!-- 

<view bindtap="viewTapped" >{{message}}</view> 

-->

bindtap 属性指定了一个方法名,我们只需要在 Page 对象里面实现这个方法就可以处理用户的点击操作了:

Page({

  viewTapped: function() {

    console.log('hello world.')

  }

})

当然, Page 还提供了修改它内部数据的方法 —— setData, 我们可以在刚才这个点击事件中使用 setData 修改显示在前端中的文字:

Page({

  viewTapped: function() {

    this.setData({

      message: '你好, 世界'

    });

  }

})


二:数据绑定与模块化

微信小程序的 UI 层如何与控制层交互, 以及怎么样响应用户操作事件, 这次咱们来聊聊。

WXML

微信小程序使用 WXML 文件作为 UI 视图。 WXML 其实就是 WeiXin Markup Language 的缩写。 是一种类似 XML 语法结构的 UI 定义方式。

它可以进行数据绑定, 显示 Page 中相应的属性:

<!-- 

<view> {{message}} </view>

 -->

两对括号中的 message 对应 Page 中 data 属性中的 message:

Page({

  data: {

    message: 'Hello World'

  }

})

当然, 我们还可以进行循环显示, 这个语法可能会和大家平时使用过的模板语法不太相同:

<!-- 

<view wx:for="{{array}}"> {{item}} </view>

 -->

wx:for 是微信定义的一个特殊属性, 其实相当于一个 for 循环, 重复显示 View 空间, 然后将数组中的每一个元素都遍历一遍, 下面是 array 在 Page 中的定义:

Page({

  data: {

    array: ["Swift", "Objctive-C", "Javascript"]

  }

})

上面 WXML 例子中的 代表我们 data 中的 array 数组, 而 表示的就是数组遍历中的每一个元素, 编译运行后的界面显示如下:

除了 wx:for 这种循环遍历语法之外, 微信还提供了另外一种, wx:if, 大家从名称中应该就可以想到, 它是一个条件判断, 只有当条件判断成立, 才会显示这个 View。 除了 wx:if 之外, 还提供了了 wx:elif, wx:else

<!-- 

<view wx:if="{{false}}" >Hello Title</view>

<view wx:elif="{{false}}" >Hello World</view>

<view wx:else >Hello Wechat</view>

-->

注意这三个属性的用法, wx:if 和 wx:elif 这两个属性后面需要跟随一个布尔表达式用于判断, 而 wx:else 后面不需要跟随任何表达式。 这三个属性的逻辑和我们平时开发中的 if else 判断逻辑完全一样,也比较好理解。

关于 wx:else 微信官方的示例中是给他指定了表达式属性的。 但我在真实环境上测试了一下, wx:else 无论是否指定后面的属性值,最终的输出结果都是一样的, 所以这可能是官方示例的一个笔误。 按照 if 表达式正常的逻辑来看,应该不需要给它再设属性了。 大家可以留意一下。

模板

说完了循环和条件判断语法, WXML 还支持模板定义, 比如这样:

<!-- 

<template name="hello" >

  <view>

    Hello, {{name}}

  </view>

</template>

<template is="hello" data="{{...swift}}" ></template>

<template is="hello" data="{{...objc}}" ></template>

-->

简单解释一下, 第一个 template 标签是模板定义, name 属性定义了它的名字,在两个标签之间是它的内部结构。 然后紧接着的后两个 template 标签是模板的引用, is 属性代表要引用哪个模板。 我们这里填入的都是 hello, 也就是我们最开始定义的这个模板结构。 然后就是 data 属性,通过它传入模板需要的相关数据。 先来开一下 swift 和 objc 这两个数据的定义:

Page({

  data: {    

    swift: { name: "Swift"}, 

    objc: { name: "Objective-C"}

  }

})

swift 和 objc 都是两个 JSON 对象, 都包含一个 name 属性。 大家注意看我们前面模板引用 data 属性的方式:

<!-- <template is="hello" data="{{...swift}}" ></template> -->

这里我们在一对大括号中的变量名前面还写了三个点 —— …

… 其实是一个操作符, 用于将 swift 变量内部的值 “展开”, 这么说可能不太好理解, 咱们还回到模板的定义中:

<!-- 

<template name="hello" >

  <view>

    Hello, {{name}}

  </view>

</template>

-->

我们看到, template 内部使用 来引用我们传入对象的属性。 这就需要我们 “展开” 传入的对象, 才能让模板找到对应 key 的值。 简单来说, 如果我们不适用 … 这个操作符,而是直接像这样传入对象:

<!-- 

<template is="hello" data="{{swift}}" ></template> 

-->

如果这样运行程序的话, 模板是不能正确读取到 name 属性的。

模板的引用

当然, 我们可以不用把模板的定义和引用它的代码写到一起, 我们可以把模板的定义单独写在一个 WXML 文件中, 然后在另外一个文件中使用 import 来引入它。 这也是一个结构良好的项目的通常做法。 比如我们刚才的模板存放到 hello.wxml 中, 我们就可以这样引用它:

<!--

<import src="hello.wxml" />

<template is="hello" data="{{...swift}}" ></template>

<template is="hello" data="{{...objc}}" ></template>

-->

这样我们可以比较好的进行模块划分。 当然, 除了 import 之外, 微信还给我们提供了另外一种引用方式, include。 简而言之, 他们之间的区别是这样, import 只能引入目标文件中的 template 定义, 不会引入具体的 UI 内容。 而 include 正好相反, 它只会引入目标文件中的内容,不会引入 template 定义, 比如我们有一个文件,叫做 header.wxml:

<!-- 

<view>Header Title</view>

-->

然后我们在 index.wxml 中这样引用:

<!--

<include src="header.wxml" />

<view>Hello world!</view>

-->

这样就会引入 header.wxml 中定义的内容了, 最后的输出结果就是他们两个文件中所有 UI 组件的整合了。 这就是 import 和 include 的区别了。