基本文件
小程序包含一个描述整体程序的 app 和多个描述各自页面的 page。
一个小程序主体部分由三个文件组成,必须放在项目的根目录,如下:
| 文件 | 必需 | 作用 |
|---|---|---|
| app.js | 是 | 小程序逻辑 |
| app.json | 是 | 小程序公共配置 |
| app.wxss | 否 | 小程序公共样式表 |
一个小程序页面由四个文件组成,分别是:
| 文件类型 | 必需 | 作用 |
|---|---|---|
| js | 是 | 页面逻辑 |
| wxml | 是 | 页面结构 |
| json | 否 | 页面配置 |
| wxss | 否 | 页面样式表 |
注意:为了方便开发者减少配置项,描述页面的四个文件必须具有相同的路径与文件名
全局配置
小程序根目录下的 app.json 文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。
以下是一个包含了部分常用配置选项的 app.json :
{
"pages": [
"pages/index/index",
"pages/logs/index"
],
"window": {
"navigationBarTitleText": "Demo"
},
"tabBar": {
"list": [{
"pagePath": "pages/index/index",
"text": "首页"
}, {
"pagePath": "pages/logs/index",
"text": "日志"
}]
},
"networkTimeout": {
"request": 10000,
"downloadFile": 10000
},
"debug": true
}
页面配置
每一个小程序页面也可以使用同名 .json 文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.json 的 window 中相同的配置项。
完整配置项说明请参考小程序页面配置
例如:
{
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "微信接口功能演示",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light"
}
响应的数据绑定
框架的核心是一个响应的数据绑定系统,可以让数据与视图非常简单地保持同步。当做数据修改的时候,只需要在逻辑层修改数据,视图层就会做相应的更新。
通过这个简单的例子来看:
<!-- This is our View -->
<view> Hello {{name}}! </view>
<button bindtap="changeName"> Click me! </button>
// This is our App Service.
// This is our data.
var helloData = {
name: 'Weixin'
}
// Register a Page.
Page({
data: helloData,
changeName: function(e) {
// sent data change to view
this.setData({
name: 'MINA'
})
}
})
- 开发者通过框架将逻辑层数据中的
name与视图层的name进行了绑定,所以在页面一打开的时候会显示Hello Weixin!; - 当点击按钮的时候,视图层会发送
changeName的事件给逻辑层,逻辑层找到并执行对应的事件处理函数; - 回调函数触发后,逻辑层执行
setData的操作,将data中的name从Weixin变为MINA,因为该数据和视图层已经绑定了,从而视图层会自动改变为Hello MINA!。
在vue中,只需要再表单元素上加上 v-model,然后再绑定 data中对应的一个值,当表单元素内容发生变化时, data中对应的值也会相应改变,这是vue非常nice的一点。
取值
vue中,通过 this.xxx取值。
小程序中,通过 this.data.xxx取值。
注册小程序
每个小程序都需要在 app.js 中调用 App 方法注册小程序实例,绑定生命周期回调函数、错误监听和页面不存在监听函数等。
// 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'
})
整个小程序只有一个 App 实例,是全部页面共享的。开发者可以通过 getApp 方法获取到全局唯一的 App 实例,获取 App 上的数据或调用开发者注册在 App 上的函数。
// xxx.js
const appInstance = getApp()
console.log(appInstance.globalData) // I am global data
生命周期
- onload 监听页面加载
- onready 监听页面初次渲染完成
- 一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。
- onshow 监听页面显示
- onhide 监听页面隐藏
- 当 navigateTo或底部tab切换时调用。
- onunload 监听页面卸载
- 当 redirectTo或 navigateBack的时候调用。
数据请求
在页面加载请求数据时,两者钩子的使用有些类似,vue一般会在 created或者 mounted中请求数据,而在小程序,会在 onLoad或者 onShow中请求数据。
页面路由
路由方式
对于路由的触发方式以及页面生命周期函数如下:
| 路由方式 | 触发时机 | 路由前页面 | 路由后页面 |
|---|---|---|---|
| 初始化 | 小程序打开的第一个页面 | onLoad, onShow | |
| 打开新页面 | 调用 API wx.navigateTo 使用组件 <navigator open-type="navigateTo"/> | onHide | onLoad, onShow |
| 页面重定向 | 调用 API wx.redirectTo 使用组件 <navigator open-type="redirectTo"/> | onUnload | onLoad, onShow |
| 页面返回 | 调用 API wx.navigateBack 使用组件<navigator open-type="navigateBack"> 用户按左上角返回按钮 | onUnload | onShow |
| Tab 切换 | 调用 API wx.switchTab 使用组件 <navigator open-type="switchTab"/> 用户切换 Tab | 各种情况请参考下表 | |
| 重启动 | 调用 API wx.reLaunch 使用组件 <navigator open-type="reLaunch"/> | onUnload | onLoad, onShow |
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() |
注意事项
navigateTo,redirectTo只能打开非 tabBar 页面。switchTab只能打开 tabBar 页面。reLaunch可以打开任意页面。- 页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
- 调用页面路由带的参数可以在目标页面的
onLoad中获取。
小程序中,全用 bindtap(bind+event),或者 catchtap(catch+event)绑定事件,例如:
<button bindtap=``"noWork"``>明天不上班</button>
<button catchtap=``"noWork"`` >明天不上班</button> ``//阻止事件冒泡
绑定事件传参
在 小程序中,不能直接在绑定事件的方法中传入参数,需要将参数作为属性值,绑定到元素上的 data-属性上,然后在方法中,通过 e.currentTarget.dataset.*的方式获取,从而完成参数的传递,很麻烦有没有...
<view class='tr' bindtap='toApprove' data-id="{{item.id}}"></view>
Page({
data:{
reason:''
},
toApprove(e) {
let id = e.currentTarget.dataset.id;
}
})
父子组件通信
<tab-bar currentpage="index"></tab-bar>
此处, “index”就是要向子组件传递的值
在子组件 properties中,接收传递的值。
properties: {
// 弹窗标题
currentpage: { // 属性名
type: String, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
value: 'index' // 属性初始值(可选),如果未指定则会根据类型选择一个
}
}
子组件向父组件通信和 vue也很类似,代码如下:
//子组件中
methods: {
// 传递给父组件
cancelBut: function (e) {
var that = this;
var myEventDetail = { pickerShow: false, type: 'cancel' } // detail对象,提供给事件监听函数
this.triggerEvent('myevent', myEventDetail) //myevent自定义名称事件,父组件中使用
},
}
//父组件中
<bar bind:myevent="toggleToast"></bar>
// 获取子组件信息
toggleToast(e){
console.log(e.detail)
}
如果父组件想要调用子组件的方法
小程序是给子组件添加 id或者 class,然后通过 this.selectComponent找到子组件,然后再调用子组件的方法,示例:
//子组件
<bar id="bar"></bar>
// 父组件
this.selectComponent('#id').syaHello()