Skip to content

页面交互

Page() 函数

在网页开发中,仅有页面结构和样式的静态页面缺少互动,难以吸引用户的关注,因而开发者常常会在页面中加入页面交互,使用户既能了解网页内容,又能增强其参与感,吸引用户驻足。
在微信小程序中也存在类似的问题。

在微信小程序中,页面交互的代码写在页面的 JS 文件中,每个页面都需要通过 Page() 函数进行注册。
需要注意的是,Page() 函数只能写在微信小程序每个页面对应的 JS 文件中,并且每个页面只能注册一个

Page() 函数的参数是一个对象,通过该对象可以指定页面初始数据、页面声明周期回调函数和页面事件处理函数。
调用 Page() 函数的示例代码如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Page({
    // 页面初始数据
    data: {},
    // 页面声明周期回调函数,以 onLoad() 为例
    onLoad: function() {
        console.log('onLoad() 函数执行了')
    },
    // 页面事件处理函数,以 onPullDownRefresh() 为例
    onPullDownRefresh: function() {
        console.log('onPullDownRefresh() 函数执行了')
    }
})

上述代码在 Page() 函数的参数中定义了页面初始数据 data、页面声明周期回调函数 onLoad() 和页面事件处理函数 onPullDownRefresh()

了解了 Page() 函数的作用后,下面对该函数中的页面初始数据、页面生命周期回调函数和页面事件处理函数分别进行讲解。

(1) 页面初始数据

页面初始数据是指页面第一次渲染时所用到的数据。

1
2
3
4
data: {
    msg1: 'Hello',
    msg2: 'World'
}

(2) 页面生命周期回调函数

在微信小程序中,页面的生命周期是指每个页面 "加载->渲染->销毁" 的过程,每个页面都有生命周期。
如果想要在某个特定的时机进行特定的处理,则可以通过页面生命周期回调函数来完成

页面生命周期回调函数用于实现在特定的时间点执行特定的操作,随着页面生命周期的变化,页面生命周期回调函数会自动执行。
常见的页面生命周期回调函数如下表所示:

函数名 说明
onLoad() 监听页面加载,且一个页面只会在创建完成后调用一次
onShow() 监听页面显示,只要页面显示就会调用此函数
onReady() 监听页面初次渲染完成,一个页面只会调用一次
onHide() 监听页面隐藏,只要页面隐藏就会调用此函数
onUnload() 监听页面卸载,只要页面被释放就会调用此函数

需要注意的是,页面声明周期回调函数监听的是当前页面的状态

(3) 页面事件处理函数

在微信小程序中,用户可能会在页面上进行一些操作,例如上拉、下拉、滚动页面等,如何在发生这些操作的时候进行处理呢?
可以通过页面事件处理函数来完成

页面事件处理函数用户监听用户的行为,常见的页面事件处理函数如下表所示:

函数名 说明
onPullDownRefresh() 监听用户下拉刷新事件
onReachBottom() 监听页面上拉触底事件
onPageScroll() 页面滚动会连续调用
onShareAppMessage() 用户点击页面右上角三个点按钮,选择 “转发给朋友” 时调用

需要注意的是,使用 onPullDownRefresh() 函数前,需要在 app.json 配置文件中将 enablePullDownRefresh 配置项设为 true。
enablePullDownRefresh 配置项表示是否当前页面下拉刷新,如果该配置项值为 true,则当前页面开启下拉刷新,否则当前页面关闭下拉刷新

数据绑定

在微信小程序开发过程中,一般会将页面中的数据从 WXML 文件中分离出来,通过 JS 文件操作页面中的数据。
那么,微信小程序为什么要将数据分离出来呢?下面我们来看一个例子。
假如有一个电商类的微信小程序,里面有大量的商品,每个商品都有一个单独的商品详情页面。
用户可以选择喜欢的商品进行查看,通过商品详情来确定是否需要购买该商品,不同的商品有不同的详情信息。

每个商品的详情页面的结构是相同的,区别是页面展示的额数据不同。
在实际开发中,开发者并不需要为每个商品单独编写一个详情页面,而是只编写一个页面,通过更改页面中的数据来实现不同的商品详情页面。
这种开发方式是将页面中的数据分离出来,放到页面的 JS 文件中,通过程序控制页面中数据的展示

将数据从页面中分离以后,如何将数据显示到页面中呢?
这就需要将 JS 文件中的数据绑定到页面中。
微信小程序提供了 Mustache 语法(又称为双大括号语法)用于实现数据绑定,可以将 data 中的数据通过 Mustache 语法输出到页面上。

下面来演示如何通过数据绑定将数据显示在页面中。
首先打开 pages/index/indeex.js 文件中,在 data 中定义一个 message 数据,具体代码如下:

1
2
3
4
5
Page({
    data: {
        message: 'Hello World'
    }
})

接下来在 pages/index/index.wxml 文件中编写页面结构,具体代码如下:

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

事件绑定

在微信小程序中,事件是视图层到逻辑层的通信方式,通过给组件绑定事件,可以监听用户的操作行为,然后在对应的事件处理函数中进行相应的业务处理。
例如,为页面中的按钮绑定事件,当用户点击按钮时,就产生了事件

在微信小程序中,常见的事件如下表所示:

类别 事件名次&触发条件
点击事件 tap: 手指触摸后马上离开
长按事件 longpress: 手指触摸后,超过 350ms 再离开,如果指定了事件回调函数并触发了这个事件,tap 事件将不被触发
触摸事件 touchstart: 手指触摸动作开发; touchmove: 手指触摸后移动; touchcancel: 手指触摸动作被打断,例如来电提醒、弹窗; touchend: 手指触摸动作结束;
其他事件 input: 键盘输入时触发; submit: 携带 form 组件中的数据触发 submit 事件

需要注意的是,微信小程序中的事件分为冒泡事件和非冒泡事件。
当一个组件上的事件被触发后,该事件会向父组件传递,这类事件为冒泡事件;
当一个组件上的事件被触发后,该事件不会向父组件传递,这类事件为非冒泡事件。
点击事件、长按事件、触摸事件都属于冒泡事件,其他事件属于非冒泡事件。

若要为组件绑定事件,可以通过为组件添加 "bind+事件名称" 属性或 "catch+事件名称" 属性来完成,属性的值为事件处理函数,当组件的事件被触发时,会主动执行事件处理函数。
bind 和 catch 的区别在于,bind 不会阻止冒泡事件向上冒泡,而 catch 可以阻止冒泡事件向上冒泡

为组件绑定事件后,可以将事件处理函数定义在 Page({}) 中,下面进行代码演示

首先在 pages/index/index.wxml 文件中为 button 组件绑定 tap 事件,事件处理函数为 compare() 函数,具体代码如下

<button bindtap="compare">比较</button>

在上述代码中,bindtap 表示绑定 tap 事件。在触屏手机中,tap 事件在用户手指触摸 button 组件离开后触发,而在微信开发者工具中,tap 事件在鼠标单击 button 组件时触发

然后在 pages/index/index.js 文件的 Page({}) 中定义 compare() 函数,具体代码如下:

1
2
3
compare: function() {
    console.log('比较按钮被单击了')
}

事件对象

在微信小程序的开发过程中,有时需要获取事件发生时的一些信息,例如事件类型、事件发生的时间、触发事件的对象等,此时可以通过事件对象来获取。

当事件处理函数被调用时,微信小程序会将事件对象以参数的形式传给事件处理函数。
事件对象的属性如下表所示:

属性 类型 说明
type string 事件类型
timeStamp number 事件生成的时间戳
target object 触发时间的组件的一些属性值集合
currentTarget object 当前组件的一些属性值集合
mark object 事件标记数据

this 关键字

在微信小程序开发过程中,有时需要在函数中访问页面中定义的一些数据,或者调用页面中定义的一些函数,此时可以通过 this 关键字来实现。
this 关键字代表当前页面对象。

下面通过代码演示 this 关键字的使用,具体代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Page({
    data: {
        num: 1
    },
    test: function() {
        console.log('test()函数执行了')
    },
    onLoad: function() {
        console.log(this.data.num)
        this.test()
    }
})

上述代码演示了如何在 onLoad() 函数中通过 this 关键字访问 data 中的 num 数据并调用 test 函数。
程序运行后,在控制台中可以看到程序输出了 this.data.num 的值 "1" 和 "test() 函数执行了"

setData() 方法

在微信小程序开发过程中,虽然通过数据绑定可以将 data 中定义的数据渲染到页面,但是如果数据发生了变化,页面并不会同步更新数据。
为了实现在数据变化时使页面同步更新,微信小程序提供了 setData() 方法,该方法可以立即改变 data 中的数据,并通过异步的方式将数据渲染到页面上

setData() 方法通过 this 关键字调用,该方法的基本语法格式如下

this.setData(data[, callback])

在上述语法中,setData() 方法有 2 个参数,具体说明如下表所示:

属性 类型 说明
data object 当前要改变的数据
callback function setData() 方法引起的页面更新渲染完毕后的回调函数

条件渲染

在微信小程序开发过程中,如果需要根据不同的判断结果显示不同的组件,可以使用条件渲来实现。
条件渲染通过标签的 wx:if 控制属性来完成。
使用 wx:if="{{ val }} 来判断是否需要渲染标签对应的组件,如果变量 val 的值为 true,则渲染组件并输出;
变量 val 的值为 false,则不渲染组件,示例代码如下:

<view wx:if="{{ condition }}">True</view>

上述代码通过 <view> 标签定义了 view 组件,并通过变量 condition 的值来控制是否渲染 view 组件

给标签设置了 wx:if 控制属性后,可以为后面的标签设置 wx:elifwx:else 控制属性。

1
2
3
<view wx:if="{{ count < 1 }}">0</view>
<view wx:elif="{{ count == 1 }}">1</view>
<view wx:else>2</view>

block 标签

当使用一个判断条件决定是否显示或者隐藏多个组件时,通常会在其外部包裹一个 view 组件,这样可直接控制这个外部 view 组件的显示或隐藏。
但是这个外层的 view 组件只是一个单纯的容器,没有其他作用,而且它会被渲染出来,导致性能消耗。
此时,可以通过 <block> 标签来创建一个容器,该标签并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接收控制属性。
<block> 标签的示例代码如下:

1
2
3
4
<block wx:if="{{ true}}">
    <view>view1</view>
    <view>view2</view>
</block>

在上述代码中,<block> 标签中 wx:if 控制属性的值为 true,在页面上会渲染出 <block> 组件内部的两个 view 组件

列表渲染

列表渲染通过 wx:for 控制属性来实现。微信小程序进行列表渲染时,会根据列表中数据的数量渲染相应数量的内容。
wx:for 控制属性所在标签的内容,可以使用 item 变量获取当前项的值,使用 index 变量获取当前项的值,使用 index 变量获取当前项的数组索引或对象属性名。
如果不想使用 item 和 index 这两个变量名,还可以通过 wx:for-item 控制属性更改 item 的变量名;
通过 wx:for-index 控制属性更改 index 的变量名

wx:for 控制属性通常搭配 wx:key 控制属性使用,wx:key 控制属性用于为每一项设置唯一标识,这样可以在数据改变后页面重新渲染时,使原有组件保持自身的状态,而不是重新创建,这样可以提高列表渲染的效率。

在设置 wx:key 的值时,如果 item 本身就是一个具有唯一性的字符串或数字,则可以将 wx:key 的值设置为 *this*this 表示 item 本身;
如果给定的数据是由对象作为数组元素构成的数组,那么可以将 wx:key 的值设置为对象中一个 "值具有唯一性" 的属性的名称。
例如,服务器返回的数据中经常包含 id 属性,该属性是数据库中每条记录的唯一标识,在微信小程序中可以使用 id 作为 wx:key 的值

下面分别讲解如何实现数据的列表渲染和数组中包含对象情况下的列表渲染。

(1) 数组的列表渲染

首先在 pages/index/index.js 文件的 Page({}) 中编写页面数据,具体代码如下

1
2
3
data: {
    arr: ['a', 'b', 'c']
}

接下来在 pages/index/index.wxml 文件中编写页面结构,通过列表渲染的方式将 arr 数组渲染到页面中,具体代码如下:

1
2
3
<view wx:for="{{ arr }}" wx:key="*this">
    {{ index }} {{ item }}
</view>

(2) 数组中包含对象情况下的列表渲染

首先在 pages/index/index.js 文件的 Page({}) 中编写页面数据,具体代码如下:

1
2
3
4
5
6
7
8
data: {
    list: [
        { message: '梅', id: 1 },
        { message: '兰', id: 2 },
        { message: '竹', id: 3 },
        { message: '菊', id: 4 },
    ]
}
1
2
3
4
<view wx:for="{{ list }}" wx:key="id">
    {{ index }}-----{{ item.message }}
    ======={{ item.id }}
</view>

如何通过 wx:for-itemwx:for-index 更改 item 和 index 的变量名:

1
2
3
<view wx:for="{{ list }}" wx:for-item="item2" wx:for-index="index2" wx:key="id">
    {{ index2 }}: {{ item2.message }}
</view>

网络请求

客户端与服务器进行交互时,客户端请求服务器的过程称为网络请求。
例如,获取用户的头像信息,需要客户端向服务器发送请求,服务器查询到数据后把数据传递给客户端。
在微信小程序中实现网络请求时,需要服务器给微信小程序提供服务器接口

出于安全性方面的考虑,微信小程序官方对服务器接口的请求做了如下两个限制

  • 只能请求 HTTPS 协议的服务器接口
  • 必须登录微信小程序管理后台,将服务器接口的域名添加到信任列表中

开发 -> 开发管理 -> 开发设置 -> 服务器域名

在微信小程序中发起网络请求可以通过调用 wx:request() 方法来实现。
wx:request() 方法常见的选项如表所示:

选项 类型 说明
url string 开发者服务器接口地址,默认值为 ""
data string/object/ArrayBuffer 请求的参数,默认值为 ""
header object 设置请求的 header,默认值为 ""
method string HTTP 请求方式,默认值为 GET
dataType string 返回的数据格式,默认值为 json
responseType string 响应的数据类型,默认值为 text
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数

下面演示如何通过 wx.request() 方法发起一个 GET 方式的请求,示例代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
wx.request({
    url: 'URL 地址',
    method: 'GET',
    data: {
        name: 'zs'
    },
    success: res => {
        console.log(res)
    }
})