记录本人在学习过程中觉得需要重复复习的点
目录
[1. 全局数据共享(Global Data)](#1. 全局数据共享(Global Data))
[3.使用 Storage(持久化存储)](#3.使用 Storage(持久化存储))
[二、 data属性值之间如何互相使用](#二、 data属性值之间如何互相使用)
[一、在 onLoad 或 onShow 中动态赋值](#一、在 onLoad 或 onShow 中动态赋值)
[二、使用 observers 监听 sharedValue 变化(动态更新)](#二、使用 observers 监听 sharedValue 变化(动态更新))
[2)使用 navigator 组件包裹图片(推荐)](#2)使用 navigator 组件包裹图片(推荐))
[2. 所在页面触发的生命周期函数(需在 pageLifetimes 中定义)](#2. 所在页面触发的生命周期函数(需在 pageLifetimes 中定义))

小程序项目代码:
一、页面之间的信息传递
1)父传子
通过 **properties
** 属性传递
javascript
// 父组件.wxml
<child-component myProp="{{parentData}}"></child-component>
// 子组件.js
Component({
properties: {
myProp: {
type: String, // 类型
value: '' // 默认值
}
},
observers: {
'myProp': function(newVal) {
// 监听属性变化
}
}
})
其中observes用来监听传递对象的某个属性值,可以对属性值进行格式化等操作或处理
javascript
Component({
properties: {
// 接收父组件传递的商品对象
goods: {
type: Object,
value: {}
},
// 接收父组件传递的索引
index: {
type: Number,
value: 0
}
},
observers: {
// 监听商品数据变化(例如价格格式化)
'goods.price'(price) {
this.setData({ formattedPrice: `¥${price.toFixed(2)}` });
}
},
html
<view class="goods-card" bind:tap="onTap">
<image src="{{goods.image}}" class="goods-image" />
<view class="goods-info">
<text class="goods-name">{{goods.name}}</text>
<text class="goods-price">{{formattedPrice}}</text>
</view>
</view>
2)子传父
javascript
// 子组件.js
this.triggerEvent('myEvent', { data: value }, { bubbles: true /* 是否冒泡 */ });
// 父组件.wxml
<child-component bind:myEvent="onMyEvent"></child-component>
// 父组件.js
Page({
onMyEvent(e) {
const value = e.detail.data; // 获取子组件传递的值
}
})
3)任意两个页面之间
1. 全局数据共享(Global Data)
通过 app.js
的 globalData
存储全局状态:
javascript
/ app.js
App({
globalData: {
sharedData: '初始值'
}
});
// 组件A.js 设置数据
const app = getApp();
app.globalData.sharedData = '新值';
B组件获取
data: {
selectedGoodsInfo: null, // 存储选中的商品信息
name:null,
},
onShow() {
// 从全局数据中获取选中的商品信息
const app = getApp();
if (app.globalData && app.globalData.selectedGoodsInfo) {
this.setData({
selectedGoodsInfo: app.globalData.selectedGoodsInfo
});
// 清除全局数据,避免影响下次选择
app.globalData.selectedGoodsInfo = null;
}
},
2.页面间数据传递
若组件位于不同页面,可通过路由参数或页面跳转传递:
javascript
//页面A传递比较复杂的参数时
// pages/pageA/pageA.js
Page({
goToPageB() {
const productId = 123;
const productName = "手机";
// 跳转并传递参数(参数拼接在 URL 中)
wx.navigateTo({
url: `/pages/pageB/pageB?id=${productId}&name=${encodeURIComponent(productName)}`
});
}
});
// 页面A跳转时传递参数
wx.navigateTo({
url: '/pages/pageB?param=123'
});
// 页面B.js 获取参数
Page({
/**
* 页面的初始数据
*/
data: {
name:null
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
const name=options.name
this.setData({
name//或者直接写为name:options.name
})
},
)}
3.使用 Storage(持久化存储)
javascript
// 组件A.js 存储数据
//wx.setStorageSync('key', 'value');
wx.setStorageSync('sharedData', newBalance);
// 页面B的 JS
Page({
data: {
sharedValue: ''
},
// 生命周期:页面加载时读取数据
onLoad() {
this.loadStorageData();
},
// 生命周期:页面显示时重新读取(确保数据最新)
onShow() {
this.loadStorageData();
},
// 读取 Storage 数据
loadStorageData() {
// 同步读取
try {
const value = wx.getStorageSync('sharedData');
if (value) {
this.setData({ sharedValue: value });
} else {
this.setData({ sharedValue: '暂无数据' });
}
} catch (error) {
console.error('读取失败:', error);
}
各种任意两个组件信息传递方式的对比:
信方式 应用场景 典型示例 适用性 全局数据(Global Data) 多个组件需要共享全局状态,且数据更新频率较低。 用户登录状态、全局配置(如主题色)、应用级别设置(如语言)。 简单场景,数据共享范围广,但需注意避免滥用(频繁更新可能导致维护困难)。 事件总线(Event Bus) 跨组件实时通知,组件间需要解耦,一对多通信。 消息推送、状态同步(如购物车数量更新)、跨页面组件联动(如A组件操作触发B组件刷新)。 复杂场景,适合组件分散、交互频繁的情况,需注意及时销毁监听避免内存泄漏。 页面间数据传递 通过路由参数或页面跳转传递一次性数据。 商品详情页跳转时传递商品ID、表单提交后返回列表页携带状态参数。 简单数据传递,仅限于页面跳转场景,数据量不宜过大(URL长度限制)。 页面实例中转 同一页面内多个独立组件需要共享临时数据,且无需持久化。 页面内的筛选组件和列表组件同步筛选条件、表单组件和预览组件实时交互。 同一页面内组件间简单通信,依赖页面实例,不适合跨页面。 Storage(本地存储) 需要持久化存储的数据,且多个组件或页面需读取同一份数据。 用户偏好设置(如夜间模式)、缓存登录凭证、离线数据暂存。 数据需要长期保存,读写频繁时注意性能(同步接口可能阻塞渲染)。 状态管理库(如MobX) 复杂应用需要集中式状态管理,支持响应式更新,跨组件/页面高效同步数据。 大型电商应用(购物车、订单状态)、实时协作类应用(如多人编辑文档)。 超复杂场景,需引入第三方库,适合中大型项目,对代码结构有较高要求。
二、 data属性值之间如何互相使用
错误写法:
javascript
data: {
sharedValue: '',
xinxi:[
{
title:"this.sharedValue",
subTitle:"我的余额",
}]
}
在微信小程序中,data
内的字段在初始化时无法直接互相引用
正确解法:
有以下几种方案来解决:
一、在 onLoad
或 onShow
中动态赋值
javascript
Page({
// ...其他代码...
onShow(){
// 从 data 中获取 sharedValue,设置到 xinxi[0].title
this.setData({
'xinxi[0].title': this.data.sharedValue
});
}
});
二、使用 observers
监听 sharedValue
变化(动态更新)
javascript
Page({
data: {
sharedValue: '默认值',
xinxi: [
{
subTitle: '我的余额',
title: '' // 初始为空,后续通过 observer 更新
}
]
},
// 监听 sharedValue 变化
observers: {
'sharedValue': function(newValue) {
this.setData({
'xinxi[0].title': newValue // 将新值赋给 title
});
}
},
// 示例:修改 sharedValue(如按钮点击事件)
updateValue() {
this.setData({
sharedValue: '新值'
});
}
});
三、生命周期函数:
1.作用:
生命周期函数用于在 特定时机自动执行代码,例如:
- 页面加载时初始化数据
- 页面显示时刷新内容
- 页面隐藏时释放资源
- 应用启动时获取用户信息
2.核心函数及执行顺序
函数名 | 触发时机 | 执行次数 | 典型场景 | 注意事项 |
---|---|---|---|---|
onLoad |
页面 首次加载(创建)时触发 | 一次 | 接收页面参数、初始化数据 | 无法操作 DOM(视图未渲染) |
onShow |
页面 显示时 触发 | 多次 | 刷新数据、更新用户状态 | 可能频繁触发(如返回页面) |
onReady |
页面 初次渲染完成 时触发 | 一次 | 操作 DOM、初始化地图/图表等组件 | 确保视图已存在 |
onHide |
页面 隐藏时 触发(跳转/切后台) | 多次 | 暂停计时器、保存临时状态 | 不可见但未被销毁 |
onUnload |
页面 销毁时 触发(关闭或跳转) | 一次 | 释放资源(如 WebSocket 连接) | 页面实例将被回收 |
首次进入页面 → onLoad → onShow → onReady
离开页面(跳转/切后台) → onHide
重新进入页面 → onShow
关闭页面 → onUnload
类型 | 函数名 | 触发时机 | 执行次数 | 核心用途 |
---|---|---|---|---|
页面 | onLoad |
页面首次加载时 | 一次 | 初始化数据、获取参数 |
onShow |
页面显示时 | 多次 | 刷新动态数据 | |
onReady |
页面初次渲染完成时 | 一次 | 操作 DOM、初始化组件 | |
onHide |
页面隐藏时 | 多次 | 暂停操作、保存临时状态 | |
onUnload |
页面销毁时 | 一次 | 释放资源 | |
应用 | onLaunch |
小程序初始化完成时 | 一次 | 全局配置、检查更新 |
onShow |
小程序启动或从后台返回时 | 多次 | 恢复应用状态 | |
onHide |
小程序切到后台时 | 多次 | 保存全局状态 |
四、路由导航
目标页面类型 | 正确 API | 说明 |
---|---|---|
普通页面 | wx.navigateTo |
保留当前页面,新页面压入页面栈 |
普通页面(不可返回) | wx.redirectTo |
关闭当前页面,打开新页面 |
导航栏(tabBar)页面 | wx.switchTab |
切换到 tabBar 页面 |
所有页面关闭后跳转 | wx.reLaunch |
关闭所有页面,打开新页面 |
API | 说明 |
---|---|
wx.navigateTo |
保留当前页面,跳转到新页面(可返回) |
wx.redirectTo |
关闭当前页面,跳转到新页面(不可返回) |
wx.switchTab |
跳转到 tabBar 页面(需在 app.json 的 tabBar 中定义) |
wx.reLaunch |
关闭所有页面,打开新页面 |
wx.navigateBack |
返回上一页或多层页面(通过 delta 参数控制) |
关于navigateBack的使用:
javascript
// /pages/payment/payment.js
Page({
onPaymentSuccess() {
// 支付成功后返回原页面
wx.navigateBack({ delta: 1 }); // 返回上一页
}
});
五、点击图片或某个组件想要实现页面跳转
1)直接绑定点击事件(最基础)
html
<image
src="/images/button.png"
mode="widthFix"
bindtap="navigateToPage"
data-url="/pages/detail/detail?id=123"
/>
javascript
Page({
navigateToPage(e) {
const url = e.currentTarget.dataset.url; // 获取 data-url 参数
wx.navigateTo({
url: url
});
}
});
2)使用 navigator
组件包裹图片(推荐)
html
<navigator url="/pages/detail/detail?id=123">
<image src="/images/button.png" mode="widthFix" />
</navigator>
3)结合前面所学组件信息传递,通过跳转实现数据传递
通过点击事件传递动态参数(如商品 ID、用户信息)。
html
<image
src="/images/product.png"
bindtap="goToDetail"
data-product-id="456"
data-type="promotion"
/>
javascript
Page({
goToDetail(e) {
const productId = e.currentTarget.dataset.productId;
const type = e.currentTarget.dataset.type;
wx.navigateTo({
url: `/pages/detail/detail?id=${productId}&type=${type}`
});
}
});
目标页面获取参数:
javascript
// /pages/detail/detail.js
Page({
onLoad(options) {
console.log(options.id); // 456
console.log(options.type); // promotion
}
});
六、自定义组件的使用
细节1:自定义组件怎么在外部定义格式
使用 externalClasses
外部样式类
组件内部:
javascript
// 自定义组件 component.js
Component({
externalClasses: ['container-class', 'title-class'], // 声明允许外部传入的类名
});
html
<!-- 组件 WXML -->
<view class="container-class">
<text class="title-class">标题</text>
<slot></slot>
</view>
使用该组件的外部:
(注意:如果组件内部定义了样式,想要覆盖不要忘了加 !important)
html
<!-- 页面 WXML -->
<custom-component
container-class="custom-container"
title-class="custom-title"
/>
css
/* 页面 WXSS */
.custom-container {
padding: 20rpx;
background: #f5f5f5;
}
.custom-title {
color: #007bff;
font-size: 32rpx;
}
细节2:自定义组件的生命周期
组件的生命周期函数分为两类:组件自身生命周期 和 所在页面触发的生命周期。以下是核心函数:
1.组件自身生命周期函数
生命周期函数 | 触发时机 | 执行次数 | 典型场景 |
---|---|---|---|
created |
组件实例 刚创建 时触发 | 一次 | 初始化非响应式数据(非 data 字段) |
attached |
组件 被添加到页面节点树 时触发 | 一次 | 访问父组件数据、初始化与页面相关的逻辑 |
ready |
组件 视图层布局完成 后触发 | 一次 | 操作 DOM、初始化第三方库(如地图) |
moved |
组件 被移动到节点树其他位置 时 | 多次 | 极少数场景(如动态调整节点顺序) |
detached |
组件 被从页面节点树移除 时触发 | 一次 | 清理定时器、取消事件监听 |
2. 所在页面触发的生命周期函数 (需在 pageLifetimes
中定义)
生命周期函数 | 触发时机 | 典型场景 |
---|---|---|
show |
组件所在页面 显示时 触发 | 刷新数据、恢复动画 |
hide |
组件所在页面 隐藏时 触发 | 暂停动画、保存临时状态 |
resize |
组件所在页面 尺寸变化时 触发 | 调整布局(如屏幕旋转) |
书写方法:
javascript
// components/my-component/my-component.js
Component({
// 组件自身生命周期
lifetimes: {
created() {
console.log('组件实例刚创建,此时还不能调用 setData');
this.internalData = '非响应式数据'; // 适合初始化非 data 字段
},
attached() {
console.log('组件被添加到页面节点树');
const parentData = this.getPageData(); // 获取父页面数据示例
this.setData({ parentData });
},
ready() {
console.log('组件视图层渲染完成');
this.initMap(); // 初始化地图组件
},
detached() {
console.log('组件被移除');
clearInterval(this.timer); // 清理定时器
}
},
// 页面触发的生命周期
pageLifetimes: {
show() {
console.log('页面显示,组件恢复');
this.resumeAnimation(); // 恢复动画
},
hide() {
console.log('页面隐藏,组件暂停');
this.pauseAnimation(); // 暂停动画
},
resize(size) {
console.log('页面尺寸变化', size);
this.adjustLayout(); // 调整布局
}
},
methods: {
// 自定义方法
getPageData() {
const pages = getCurrentPages();
return pages[pages.length - 1].data;
},
initMap() {
this.mapCtx = wx.createMapContext('map', this);
}
}
});
细节3.实例:
接下来以我封装的组件为例进行细节拆分
wxml
html
<!--components/goods.wxml-->
<view style="width: 95%;margin: 25rpx auto;background-color: white; border-radius: 5px;box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.08);height: 220rpx;position: relative;" class="custom-class" wx:for="{{goods}}" wx:key="index" use-slot>
<slot name="{{'good'+index}}"></slot>
<van-button round type="info" style="position: absolute;right: 20rpx;bottom: 20rpx;" wx:if="{{isShow}}" bind:tap="onSelectItem" data-index="{{index}}">{{btncont}}</van-button>
</view>
js
javascript
Component({
externalClasses: ['custom-class', 'title-class', 'content-class'],
options:{
//设置当前自定义组件使用多插槽模式,默认为false
multipleSlots:true
},
/**
* 组件的属性列表
*/
properties: {
goodsNum:{
type:Number,
value:4
},
isShow:{
type:Boolean,
value:true
},
btncont:{
type:String,
value:"去评价"
}
},
/**
* 组件的初始数据
*/
data: {
goods:[]
},
lifetimes:{
attached(){
//代表该组件被初始化并且加载,此时完成数组的数据添加操作
let items = [];
for(let i = 0; i < this.properties.goodsNum; i++){
items.push(i);
}
//setData微信小程序用来修改data数据的方法,该方法会将给定的对象和data原来的数据进行对象合并,合并之后强制页面进行动态刷新
this.setData({
goods: items
});
}
},
/**
* 组件的方法列表
*/
methods: {
// 处理选择按钮点击
onSelectItem(e) {
const index = e.currentTarget.dataset.index;
// 触发自定义事件,将选中的index传递给父页面
this.triggerEvent('selectItem', { index });
}
}
})
data和properties区别
特性 | **data ** |
**properties ** |
---|---|---|
定义位置 | 组件内部的 data 字段 |
组件内部的 properties 字段 |
用途 | 存储组件 内部状态 | 接收 父组件传递的只读参数 |
初始化时机 | 组件创建时初始化 | 父组件传递数据时初始化(未传则用默认值) |
数据来源 | 组件内部定义 | 父组件通过属性传入 |
可修改性 | 组件内部可通过 setData 修改 |
不可直接修改(需父组件更新) |
类型校验 | 无 | 支持类型校验(type 字段) |
默认值设置 | 直接在 data 中赋值 |
通过 value 字段设置默认值 |
通过传入的goodsNum,结合wx:for的使用即实现了创建不同多个商品数量。
那么在外部当中怎么像插槽当中传入数据呢?
外部的使用
html
<Good goodsNum="{{2}}" btncont="去拼团" custom-class="my-custom-style" bind:selectItem="steptopintuan">
<view wx:for="{{goods}}" wx:key="index" slot="{{'good'+index}}">
<image src="{{item.imgUrl}}" mode="widthFix" style="width: 100%;"/>
<view style="text-align: center;font-size: large;font-weight: 550;">{{item.title}}</view>
<view style="text-align: center;margin-top: 10px;color: #ccc;">{{item.subtitle}}</view>
<view style="text-align: center;margin-top: 10px;"> {{item.time}}</view>
<view style="text-align: left;margin-top: 10px; display: flex;">
<view style="color: red;padding-left: 25px;"> {{item.price}} </view>
<view style="color: #ccc;padding-left:25px;text-decoration: line-through"> {{item.oldprice}} </view>
<view style="color: #ccc; margin-left: 30px;">已团{{item.sales}}件</view>
</view>
</view>
</Good>
通过slot="{{}}"实现对应的绑定即可。
后续想到再补充......