微信小程序——逻辑层 App Service

逻辑层 App Service

逻辑层将数据进行处理后发送给视图层,同时接受视图层的事件反馈。
开发者写的所有代码最终将会打包成一份JavaScript文件,并在小程序启动的时候运行,直到小程序销毁。这一行为类似 ServiceWorker,所以逻辑层也称为 App Service。
JavaScript的基础上,新增了一些功能,以方便小程序的开发:

  • 增加 App 和 Page 方法,进行程序和页面的注册。
  • 增加getAppgetCurrentPages方法,分别用来获取App实例和当前页面栈。
  • 提供丰富的API,如微信用户数据,扫一扫,支付等微信特有功能。
  • 每个页面有独立的作用域,并提供模块化能力。

注:小程序框架的逻辑层并非运行在浏览器中,因此JavaScript在web中一些能力都无法使用。如windowdocument

小程序

App(Object)

App()函数用来注册一个小程序。接受一个object参数,其指定小程序的生命周期回调等。

App()必须在app.js中调用,必须调用且只能调用一次。不然会出现无法预期的后果。
微信小程序——逻辑层 App Service_第1张图片
后台:当用户点击右上角关闭,或者按了设备Home键离开微信,小程序并没有直接销毁,而是进入了后台;
前台:当再次进入微信或再次打开小程序,又会从后台进入前台。
注:只有当小程序进入后台一定时间,或者系统资源占用过高,才会被真正的销毁。

//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'
})

onPageNotFound(Object)

App({
	onPageNotFound(res) {
		wx.redirectTo({
			url: 'pages/...'
		}) // 如果是 tabbar 页面,请使用 wx.switchTab
	}
})

getApp(Object)

全局的getApp()函数可以用来获取到小程序App实例。

字段 类型 说明 最低版本
allowDefault Boolean App未定义时返回默认实现。当App被调用时,默认实现中定义属性会被覆盖合并到App中。一般用于独立分包。 2.2.4
// other.js
const appInstance = getApp()
console.log(appInstance.globalData) // I am global data

注意

  • 不要定义于App()内的函数中调用getApp(),使用this就可以拿到app实例。
  • 通过getApp()获取实例之后,不要私自调用生命周期函数。

场景值

基础库 1.1.0 开始支持,低版本需做兼容处理

  • 对于小程序,可以在ApponLaunchonShow,或wx.getLaunchOptionsSync中获取上述场景值。
  • 对于小游戏,可以在wx.getLaunchOptionsSyncwx.onShow中获取上述场景值

部分场景值下还可以获取来源应用、公众号或小程序的appId。
由于安卓系统限制,目前还无法获取到按Home键退出到桌面,然后从桌面再次进小程序的场景值,对于这种情况,会保留上一次的场景值

页面Page

Page(Object)构造器

Page(Object) 函数用来注册一个页面。接受一个Object类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。
Object 参数说明:
微信小程序——逻辑层 App Service_第2张图片
示例代码:

Page({
  data: {
    text: 'This is page data.'
  },

  onLoad(options) {
    // do some initialize when page load
  },

  onReady() {
    // do something when page ready.
  },

  onShow() {
    // do something when page show
  },

  onHide() {
    // do something when page hide.
  },

  onUnload() {
    // do something when page close.
  },

  onPullDownRefresh() {
    // do something when pull down
  },

  onReachBottom() {
    // do something when page reach bottom.
  },

  onShareAppMessage() {
    // return custom share data when user share.
  },

  onPageScroll() {
    // do something when page scroll.
  },

  onResize() {
    // do something when page resize
  },

  onTabItemTap(item) {
    console.log(item.index)
    console.log(item.pagePath)
    console.log(item.text)
  },

  // event handler.
  viewTap() {
    this.setData({
      text: 'set some data for updating view.'
    },function() {
      // this is setData callback
    })
  },
  customData: {
    hi: 'MINA'
  }
})

除了Page,作为高级用法,页面可以像自定义组件一样使用Component来创建,这样可以使用自定义组件的特性,如behaviors等。

data

data 是页面第一次渲染使用的初始数据

页面加载时,data将会以JSON字符串的形式由逻辑层传至渲染层,因此data中的数据必须是可以转成JSON的类型:字符串,数字,布尔值,对象,数组。

渲染层可以通过WXML对数据进行绑定。

<view>{{ text }}view>
<view>{{ array[0].msg }}view>
Page({
	data: {
		text: 'init data',
		array: [{msg:'1'},{msg: '2'}]
	}
})

微信小程序——逻辑层 App Service_第3张图片
微信小程序——逻辑层 App Service_第4张图片

onShareAppMessage(Object)
Page({
	onShareAppMessage(res) {
		if(res.from === 'button') {
			// 来自页面内转发按钮
			console.log(res.target)
	}
	return {
		title: '自定义转发标题',
		path: '/page/user?id=123'
	   }
    }
})

onTabItemTap(Object)
Page({
	onTabItemTap(item) {
		console.log(item.index)
		console.log(item.pagePath)
		console.log(item.text)
	}
})

组件事件处理函数

Page 中还可以定义组件事件处理函数。在渲染层的组件中加入事件绑定,当事件被触发时,就会执行 Page 中定义的事件处理函数。

click meview>
Page({
	viewTap() {
		console.log('view tap')
	}
})

Page.route

基础库 1.2.0 开始支持,低版本需做兼容处理。

到当前页面的路径,类型为String

Page({
	onShow() {
		console.log(this.route)
	}
})

Page.prototype.setData(Object data, Function callback)

setData 函数用于将数据从逻辑层发送到视图层(异步),同时改变对应的this.data的值(同步)。

参数说明

字段 类型 必填 描述 最低版本
data Object 这次要改变的数据
callback Function setData引起的界面更新渲染完毕后的回调函数 1.5.0

Objectkey: value 的形式表示,将 this.data 中的 key 对应的值改变成 value

其中key可以以数据路径的形式给出,支持改变数组中的某一项或对象的某个属性,如array[2].messagea.b.c.d,并且不需要在this.data中预先定义。

注意:

  1. 直接修改this.data而不调用this.setData是无法改变页面的状态的,还会造成数据不一致。
  2. 仅支持设置可JSON化的数据。
  3. 单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。
  4. 请不要把data中任何一项的value设为undefined,否则这一项将不被设置并可能遗留一些潜在问题。
<view>{{text}}view>
<button bindtap="changeText">Change normal databutton>
<view>{{num}}view>
<button bindtap="changeNum">Change normal numbutton>
<view>{{array[0].text}}view>
<button bindtap="changeItemInArray">Change Array databutton>
<view>{{object.text}}view>
<button bindtap="changeItemInObject">Change Object databutton>
<view>{{newField.text}}view>
<button bindtap="addNewField">Add new databutton>
Page({
  data: {
    text: 'init data',
    num: 0,
    array: [{text: 'init data'}],
    object: {
      text: 'init data'
    }
  },
  changeText() {
    // this.data.text = 'changed data' // 不要直接修改 this.data
    // 应该使用 setData
    this.setData({
      text: 'changed data'
    })
  },
  changeNum() {
    // 或者,可以修改 this.data 之后马上用 setData 设置一下修改了的字段
    this.data.num = 1
    this.setData({
      num: this.data.num
    })
  },
  changeItemInArray() {
    // 对于对象或数组字段,可以直接修改一个其下的子字段,这样做通常比修改整个对象或数组更好
    this.setData({
      'array[0].text': 'changed data'
    })
  },
  changeItemInObject() {
    this.setData({
      'object.text': 'changed data'
    })
  },
  addNewField() {
    this.setData({
      'newField.text': 'new data'
    })
  }
})

生命周期

Page 实例的生命周期
微信小程序——逻辑层 App Service_第5张图片

路由

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

页面栈

框架以栈的形式维护了当前的所有页面。当发生路由切换的时候,页面栈的表现如下:
微信小程序——逻辑层 App Service_第6张图片

getCurrentPages()

getCurrentPages()函数用户获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。

注意:

  • 不要尝试修改页面栈,会导致路由以及页面状态错误。
  • 不要在App.onLaunch的时候调用getCurrentPages(),此时page还没有生成。

路由方式

对于路由的触发方式以及页面生命周期函数如下:
微信小程序——逻辑层 App Service_第7张图片
示例:
Tab 切换对应的生命周期(以 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()

Tips:

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

文件作用域

在JavaScript 文件中声明的变量和函数只在该文件中有效;不同的文件中可以声明相同名字的变量和函数,不会互相影响。

通过全局函数getApp()可以获取全局的应用实例,如果需要全局的数据可以在App()中设置,如:

// app.js
App({
  globalData: 1
})
// a.js
// The localValue can only be used in file a.js.
const localValue = 'a'
// Get the app instance.
const 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.
const localValue = 'b'
// If a.js it run before b.js, now the globalData shoule be 2.
console.log(getApp().globalData)

模块化

可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过module.exports或者exports才能对外暴露接口。

需要注意的是:

  • exportsmodule.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(path)将公共代码引入

const common = require('common.js')
Page({
	helloMINA() {
		common.sayHello('MINA')
	},
	goodbyeMINA() {
		common.sayGoodbye('MINA')
    }
})

Tips

  1. tip: require 暂时不支持绝对路径

相对路径:指由这个文件所在的路径引起的跟其他文件(或文件夹)的路径关系,网页结构设计中多采用这种方法来表示目标的路径。

  • ./:代表文件所在的目录(可以省略不写)
  • ../:代表文件所在的父级目录
  • ../../:代表文件所在的父级目录的父级目录
  • /:代表文件所在的根目录(可以理解成项目内部的绝对路径)

绝对路径:指目录下的绝对位置,直接到达目标位置,通常是从盘符开始的路径。

API

小程序开发框架提供丰富的微信原生API,可以方便的调起微信提供的能力,如获取用户信息,本地存储,支付功能等。


小程序 API 有以下几种类型:

事件监听 API

on开头的 API 用来监听某个事件是否触发,如:wx.onSocketOpenwx.onCompassChange等。
这类 API 接受一个回调函数作为参数,当事件触发时会调用这个回调函数,并将相关数据以参数形式传入。

wx.onCompassChange(function (res) {
	console.log(res.direction)
})

同步 API

Sync结尾的 API 都是同步 API,如wx.setStorageSyncwx.getSystemInfoSync等。此外,也有一些其他的同步 API,如 wx.createWorkerwx.getBackgroundAudioManager等。

同步 API 的执行结果可以通过函数返回值直接获取,如果执行出错会抛出异常。

try {
	wx.setStorageSync('key', 'value')
} catch (e) {
	console.error(e)
}

异步 API

大多数 API 都是异步 API,如wx.requestwx.login等。这类 API 接口通常都接受一个 Object类型的参数,这个参数都支持按需指定以下字段来接收接口调用结果:

Object 参数说明

参数名 类型 必填 说明
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)
其他 Any - 接口定义的其他参数

回调函数的参数
successfailcomplete函数调用时会传入一个Object类型参数,包含以下字段:

属性 类型 说明
errMsg string 错误信息,如果调用成功返回${ apiName }:ok
errCode number 错误码,仅部分 API 支持,具体含义请参考对应 API 文档,成功时为0
其他 Any 接口返回的其他数据

异步 API 的执行结果需要通过Object类型的参数中传入的对应回调函数获取。部分异步 API 也会有返回值,可以用来实现更丰富的功能,如wx.requestwx.connectSockets等。

wx.login({
	success(res) {
		console.log(res.code)
	}
})

你可能感兴趣的:(小程序)