微信小程序页面交互 —— 知识点详解与案例实现


一、Page() 函数

1.1 语法说明

Page() 是微信小程序用于注册页面的函数,接收一个对象作为参数,该对象包含页面的初始数据、生命周期函数、事件处理函数等。

Page({
data: { /* 页面初始数据 */ },
onLoad() { /* 页面加载时执行 */ },
onShow() { /* 页面显示时执行 */ },
// 自定义方法
handleClick() { }
})

1.2 案例:页面初始化数据

// pages/index/index.js
Page({
data: {
title: '欢迎使用小程序',
count: 0
},
onLoad() {
console.log('页面加载完成');
}
})
<!-- pages/index/index.wxml -->
<view>{{title}}</view>
<view>计数:{{count}}</view>

二、数据绑定

2.1 语法说明

使用双大括号 {{}} 在 WXML 中绑定 JS 中 data 的数据。

2.2 案例:动态显示用户名

Page({
data: {
userName: '张三'
}
})
<view>你好,{{userName}}!</view>

三、事件绑定

3.1 语法说明

在 WXML 中使用 bindcatch 绑定事件,如 bindtap 表示点击事件。

3.2 案例:点击按钮增加计数

Page({
data: {
count: 0
},
increment() {
this.setData({
count: this.data.count + 1
});
}
})
<view>当前计数:{{count}}</view>
<button bindtap="increment">+1</button>

四、事件对象

4.1 语法说明

事件处理函数会自动接收一个 event 对象,包含事件信息,如 target.dataset

4.2 案例:获取按钮自定义数据

Page({
handleClick(e) {
console.log('按钮ID:', e.currentTarget.dataset.id);
}
})
<button data-id="btn1" bindtap="handleClick">按钮1</button>

五、this 关键字

5.1 说明

在 Page 对象的方法中,this 指向当前页面实例,可用于访问 data 或调用 setData()

注意:在回调函数中(如 setTimeout),this 可能丢失,需用箭头函数或缓存 this

5.2 案例:正确使用 this

Page({
data: { msg: 'Hello' },
showMsg() {
console.log(this.data.msg); // 正确
},
delayedMsg() {
const that = this; // 缓存 this
setTimeout(function() {
that.setData({ msg: 'Delayed Hello' });
}, 1000);
}
})

六、setData() 方法

6.1 语法说明

用于修改 data 中的数据并触发页面重新渲染。不能直接修改 this.data

this.setData({
key: newValue
})

6.2 案例:更新用户输入

Page({
data: {
inputVal: ''
},
onInput(e) {
this.setData({
inputVal: e.detail.value
});
}
})
<input bindinput="onInput" value="{{inputVal}}" />
<view>你输入了:{{inputVal}}</view>

七、条件渲染(wx:if / wx:elif / wx:else)

7.1 语法说明

根据条件决定是否渲染某块内容。

7.2 案例:根据分数显示等级

Page({
data: {
score: 85
}
})
<view wx:if="{{score >= 90}}">优秀</view>
<view wx:elif="{{score >= 70}}">良好</view>
<view wx:else>需努力</view>

八、<block> 标签

8.1 说明

<block> 是一个逻辑容器,不会被渲染为真实节点,常用于包裹多个元素进行条件或列表渲染。

8.2 案例:条件渲染多个元素

<block wx:if="{{showDetails}}">
<view>姓名:张三</view>
<view>年龄:25</view>
</block>

九、hidden 属性

9.1 说明

hidden="{{true}}" 会隐藏元素,但元素仍存在于 DOM 中(与 wx:if 不同)。

9.2 案例:切换显示/隐藏

Page({
data: {
isHidden: false
},
toggle() {
this.setData({
isHidden: !this.data.isHidden
});
}
})
<view hidden="{{isHidden}}">这段文字可被隐藏</view>
<button bindtap="toggle">切换显示</button>

十、data-* 自定义属性

10.1 说明

在元素上定义 data-xxx 属性,可在事件对象中通过 e.currentTarget.dataset.xxx 获取。

10.2 案例:计算器按钮传递操作符

<button data-op="+" bindtap="handleOp">+</button>
<button data-op="-" bindtap="handleOp">-</button>
Page({
handleOp(e) {
const op = e.currentTarget.dataset.op;
console.log('操作符:', op);
}
})

十一、模块(module.exports / require)

11.1 说明

小程序支持 CommonJS 模块系统,可将工具函数封装为模块。

11.2 案例:数学工具模块

// utils/math.js
function add(a, b) {
return a + b;
}
module.exports = { add };
// pages/index/index.js
const math = require('../../utils/math.js');
Page({
onLoad() {
console.log(math.add(2, 3)); // 5
}
})

十二、列表渲染(wx:for)

12.1 语法说明

使用 wx:for 遍历数组或对象,wx:key 用于提升性能。

12.2 案例:美食列表

Page({
data: {
foods: [
{ id: 1, name: '红烧肉', price: 38 },
{ id: 2, name: '宫保鸡丁', price: 28 }
]
}
})
<view wx:for="{{foods}}" wx:key="id">
  {{index + 1}}. {{item.name}} - ¥{{item.price}}
</view>

十三、网络请求(wx.request)

13.1 案例:获取远程美食数据

Page({
onLoad() {
wx.request({
url: 'https://api.example.com/foods',
success: (res) => {
this.setData({ foods: res.data });
},
fail: () => {
wx.showToast({ title: '加载失败', icon: 'none' });
}
});
}
})

十四、提示框(wx.showToast / wx.showModal)

14.1 案例:提交问卷后提示

wx.showToast({
title: '提交成功',
icon: 'success',
duration: 1500
});

十五、WXS(WeiXin Script)

15.1 说明

WXS 是小程序的脚本语言,用于在 WXML 中处理逻辑(类似过滤器)。

15.2 案例:格式化价格

// utils/format.wxs
var formatPrice = function(price) {
return '¥' + price.toFixed(2);
}
module.exports = { formatPrice };
<wxs src="./utils/format.wxs" module="fmt" />
  <view wx:for="{{foods}}" wx:key="id">
  {{item.name}} - {{fmt.formatPrice(item.price)}}
</view>

十六、上拉触底(onReachBottom)

16.1 案例:加载更多美食

Page({
data: {
page: 1,
foods: []
},
onLoad() {
this.loadFoods();
},
onReachBottom() {
this.setData({ page: this.data.page + 1 });
this.loadFoods();
},
loadFoods() {
// 模拟请求
const newFoods = [...Array(5)].map((_, i) => ({
id: this.data.page * 5 + i,
name: `美食${this.data.page * 5 + i}`,
price: 20 + i
}));
this.setData({ foods: [...this.data.foods, ...newFoods] });
}
})

十七、下拉刷新(onPullDownRefresh)

17.1 配置与使用

// pages/food/food.json
{
"enablePullDownRefresh": true
}
Page({
onPullDownRefresh() {
this.setData({ foods: [], page: 1 });
this.loadFoods();
wx.stopPullDownRefresh(); // 停止刷新动画
}
})

十八、双向数据绑定(model:)

18.1 说明

小程序支持 model:value 实现类似 Vue 的双向绑定(需基础库 2.9.3+)。

18.2 案例:调查问卷输入

Page({
data: {
answer: ''
}
})
<input model:value="{{answer}}" placeholder="请输入答案" />
<view>你输入的是:{{answer}}</view>

注意:传统方式仍需 bindinput + setDatamodel:value 是语法糖。


综合性案例

案例1:【比较数字大小】完整实现

// pages/compare/compare.js
Page({
data: {
num1: '',
num2: '',
result: ''
},
onInput1(e) {
this.setData({ num1: e.detail.value });
},
onInput2(e) {
this.setData({ num2: e.detail.value });
},
compare() {
const n1 = parseFloat(this.data.num1);
const n2 = parseFloat(this.data.num2);
if (isNaN(n1) || isNaN(n2)) {
wx.showToast({ title: '请输入有效数字', icon: 'none' });
return;
}
let res = '';
if (n1 > n2) res = '第一个数大';
else if (n1 < n2) res = '第二个数大';
else res = '两数相等';
this.setData({ result: res });
}
})
<!-- compare.wxml -->
  <input placeholder="输入第一个数字" bindinput="onInput1" value="{{num1}}" />
  <input placeholder="输入第二个数字" bindinput="onInput2" value="{{num2}}" />
<button bindtap="compare">比较</button>
<view wx:if="{{result}}">结果:{{result}}</view>

案例2:【简易计算器】

Page({
data: {
display: '0',
firstNum: null,
operator: null,
waitingForOperand: false
},
inputDigit(e) {
const digit = e.currentTarget.dataset.digit;
if (this.data.waitingForOperand) {
this.setData({ display: digit, waitingForOperand: false });
} else {
this.setData({ display: this.data.display === '0' ? digit : this.data.display + digit });
}
},
inputOperator(e) {
const nextOperator = e.currentTarget.dataset.op;
const inputValue = parseFloat(this.data.display);
if (this.data.firstNum === null) {
this.setData({ firstNum: inputValue });
} else if (this.data.operator) {
const result = this.calculate(this.data.firstNum, inputValue, this.data.operator);
this.setData({ display: String(result), firstNum: result });
}
this.setData({ waitingForOperand: true, operator: nextOperator });
},
calculate(first, second, op) {
switch (op) {
case '+': return first + second;
case '-': return first - second;
case '*': return first * second;
case '/': return first / second;
default: return second;
}
},
clear() {
this.setData({ display: '0', firstNum: null, operator: null, waitingForOperand: false });
},
equals() {
const inputValue = parseFloat(this.data.display);
if (this.data.firstNum !== null && this.data.operator) {
const result = this.calculate(this.data.firstNum, inputValue, this.data.operator);
this.setData({ display: String(result), firstNum: null, operator: null, waitingForOperand: true });
}
}
})
<view class="display">{{display}}</view>
  <view class="row">
<button bindtap="clear">C</button>
<button data-op="*" bindtap="inputOperator">×</button>
<button data-op="/" bindtap="inputOperator">÷</button>
</view>
  <view class="row">
<button data-digit="7" bindtap="inputDigit">7</button>
<button data-digit="8" bindtap="inputDigit">8</button>
<button data-digit="9" bindtap="inputDigit">9</button>
<button data-op="-" bindtap="inputOperator"></button>
</view>
  <view class="row">
<button data-digit="4" bindtap="inputDigit">4</button>
<button data-digit="5" bindtap="inputDigit">5</button>
<button data-digit="6" bindtap="inputDigit">6</button>
<button data-op="+" bindtap="inputOperator">+</button>
</view>
  <view class="row">
<button data-digit="1" bindtap="inputDigit">1</button>
<button data-digit="2" bindtap="inputDigit">2</button>
<button data-digit="3" bindtap="inputDigit">3</button>
<button bindtap="equals">=</button>
</view>

案例3:【美食列表 + 下拉刷新 + 上拉加载】

(结合前面“列表渲染”、“网络请求”、“上拉触底”、“下拉刷新”知识点)

可参考第十二至十六节代码组合实现。


案例4:【调查问卷 + 双向绑定】

Page({
data: {
questions: [
{ id: 1, text: '你喜欢吃辣吗?', answer: '' },
{ id: 2, text: '你最喜欢的菜系?', answer: '' }
]
},
submit() {
const unanswered = this.data.questions.some(q => !q.answer.trim());
if (unanswered) {
wx.showToast({ title: '请填写所有问题', icon: 'none' });
return;
}
wx.showToast({ title: '提交成功!', icon: 'success' });
console.log('问卷结果:', this.data.questions);
},
onAnswer(e) {
const index = e.currentTarget.dataset.index;
const value = e.detail.value;
const questions = this.data.questions;
questions[index].answer = value;
this.setData({ questions });
}
})
<view wx:for="{{questions}}" wx:key="id" class="question">
<text>{{item.text}}</text>
  <input model:value="{{item.answer}}" bindinput="onAnswer" data-index="{{index}}" />
</view>
<button bindtap="submit">提交问卷</button>

本章小结

本章围绕页面交互展开,涵盖:

  • 页面注册(Page)
  • 数据驱动(data + setData)
  • 用户交互(事件绑定、事件对象)
  • 动态渲染(条件、列表、block、hidden)
  • 实用功能(网络请求、提示框、上拉/下拉)
  • 高级特性(WXS、双向绑定、模块化)

掌握这些知识点,可构建功能完整、交互流畅的小程序页面。

posted on 2025-10-16 18:16  ycfenxi  阅读(1)  评论(0)    收藏  举报