当前位置: 首页 > news >正文

微信小程序学习

记录本人在学习过程中觉得需要重复复习的点

目录

一、页面之间的信息传递

1)父传子

2)子传父

3)任意两个页面之间

1. 全局数据共享(Global Data)

2.页面间数据传递

3.使用 Storage(持久化存储)

 各种任意两个页面信息传递方式的对比:

二、 data属性值之间如何互相使用

错误写法:

正确解法:

一、在 onLoad 或 onShow 中动态赋值

二、使用 observers 监听 sharedValue 变化(动态更新)​

三、生命周期函数:

1.作用:

2.核心函数及执行顺序

 四、路由导航

五、点击图片或某个组件想要实现页面跳转

1)直接绑定点击事件(最基础)

2)使用 navigator 组件包裹图片(推荐)

3)结合前面所学组件信息传递,通过跳转实现数据传递

六、自定义组件的使用

细节1:自定义组件怎么在外部定义格式

 细节2:自定义组件的生命周期

1.组件自身生命周期函数

2. ​所在页面触发的生命周期函数​(需在 pageLifetimes 中定义)

 细节3.实例:


一、页面之间的信息传递

1)父传子

通过 ​**properties** 属性传递

// 父组件.wxml
<child-component myProp="{{parentData}}"></child-component>

// 子组件.js
Component({
  properties: {
    myProp: {
      type: String, // 类型
      value: ''     // 默认值
    }
  },
  observers: {
    'myProp': function(newVal) {
      // 监听属性变化
    }
  }
})

其中observes用来监听传递对象的某个属性值,可以对属性值进行格式化等操作或处理

Component({
  properties: {
    // 接收父组件传递的商品对象
    goods: {
      type: Object,
      value: {}
    },
    // 接收父组件传递的索引
    index: {
      type: Number,
      value: 0
    }
  },
  observers: {
    // 监听商品数据变化(例如价格格式化)
    'goods.price'(price) {
      this.setData({ formattedPrice: `¥${price.toFixed(2)}` });
    }
  },
<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)子传父

// 子组件.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 存储全局状态:

/ 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.页面间数据传递

若组件位于不同页面,可通过路由参数或页面跳转传递:


//页面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(持久化存储)

// 组件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属性值之间如何互相使用

错误写法:

data: {
    sharedValue: '',
    xinxi:[
      {
        title:"this.sharedValue",
        subTitle:"我的余额",
      }]
}

 在微信小程序中,data 内的字段在初始化时无法直接互相引用

正确解法:

有以下几种方案来解决:

一、在 onLoad 或 onShow 中动态赋值

Page({
  // ...其他代码...

  onShow(){
    // 从 data 中获取 sharedValue,设置到 xinxi[0].title
    this.setData({
      'xinxi[0].title': this.data.sharedValue
    });
  }
});

二、使用 observers 监听 sharedValue 变化(动态更新)​

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的使用:

// /pages/payment/payment.js
Page({
  onPaymentSuccess() {
    // 支付成功后返回原页面
    wx.navigateBack({ delta: 1 }); // 返回上一页
  }
});

五、点击图片或某个组件想要实现页面跳转

1)直接绑定点击事件(最基础)

<image 
  src="/images/button.png" 
  mode="widthFix" 
  bindtap="navigateToPage" 
  data-url="/pages/detail/detail?id=123" 
/>
Page({
  navigateToPage(e) {
    const url = e.currentTarget.dataset.url; // 获取 data-url 参数
    wx.navigateTo({
      url: url
    });
  }
});

2)使用 navigator 组件包裹图片(推荐)

<navigator url="/pages/detail/detail?id=123">
  <image src="/images/button.png" mode="widthFix" />
</navigator>

3)结合前面所学组件信息传递,通过跳转实现数据传递

通过点击事件传递动态参数(如商品 ID、用户信息)。

<image 
  src="/images/product.png" 
  bindtap="goToDetail" 
  data-product-id="456" 
  data-type="promotion"
/>
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}`
    });
  }
});

目标页面获取参数:

// /pages/detail/detail.js
Page({
  onLoad(options) {
    console.log(options.id);    // 456
    console.log(options.type);  // promotion
  }
});

六、自定义组件的使用

细节1:自定义组件怎么在外部定义格式

使用 externalClasses 外部样式类

组件内部:

// 自定义组件 component.js
Component({
  externalClasses: ['container-class', 'title-class'], // 声明允许外部传入的类名
});
<!-- 组件 WXML -->
<view class="container-class">
  <text class="title-class">标题</text>
  <slot></slot>
</view>

使用该组件的外部:

(注意:如果组件内部定义了样式,想要覆盖不要忘了加  !important)

<!-- 页面 WXML -->
<custom-component
  container-class="custom-container" 
  title-class="custom-title"
/>
/* 页面 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组件所在页面 ​尺寸变化时 触发调整布局(如屏幕旋转)

 书写方法:

// 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

<!--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

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的使用即实现了创建不同多个商品数量。

那么在外部当中怎么像插槽当中传入数据呢?

外部的使用

<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=“{{}}”实现对应的绑定即可。

后续想到再补充……

相关文章:

  • Docker镜像瘦身:从1GB到50MB实战
  • Leetcode 二进制求和
  • rudux中间件
  • 如何在自己的数据集上跑通DEIM(CVPR2025)
  • 深入理解垃圾收集算法:从分代理论到经典回收策略
  • 全球变暖
  • 答疑解惑:EMC VMAX3 MMCS控制台不定期重启原因分析
  • 浙大:DeepSeek技术溯源及前沿探索
  • 在SpringBoot中整合Mybatis框架
  • 实现极限网关(INFINI Gateway)配置动态加载
  • H2S Probe硫化氢荧光探针它可以通过荧光来检测H2S水平
  • Vue如何利用Postman和Axios制作小米商城购物车----简版
  • 在MFC中使用Qt(二):实现Qt文件的自动编译流程
  • 虚拟机Vmware无法连接网络
  • FFmpeg开发学习:AVFormatContext结构体
  • 【大模型基础_毛玉仁】3.4 Prompt 技巧
  • 深度学习四大核心架构:神经网络(NN)、卷积神经网络(CNN)、循环神经网络(RNN)与Transformer全概述
  • C++的IO流
  • hackmyvm-jan
  • 如何在 React 项目中使用React.lazy和Suspense实现组件的懒加载?
  • 时隔3年,持续近2小时,俄乌在土耳其谈成了什么?
  • 北方将现今年首场大范围高温天气,山西河南山东陕西局地可超40℃
  • 韩正会见美国景顺集团董事会主席瓦格纳
  • 郑钦文憾负高芙,止步WTA1000罗马站四强
  • 第一集|好饭不怕晚,折腰若如初见
  • 人民日报民生观:转人工客服,怎么这么难?