微信小程序-父子组件通信

简介: 微信小程序可有意思了

概念

在微信小程序中,子组件向父组件传递数据可以通过自定义事件的方式实现。以下是子传父的通信步骤:

  1. 在子组件中,使用 triggerEvent 方法触发自定义事件,并携带需要传递的数据。示例如下:
// 子组件的.js文件
Component({
   
  // ...
  methods: {
   
    sendDataToParent() {
   
      const data = 'Hello, parent!'; // 要传递给父组件的数据
      this.triggerEvent('customEventName', data); // 触发自定义事件并传递数据
    },
  },
});
  1. 在父组件中,使用 bind:customEventName 绑定子组件触发的自定义事件,并在对应处理函数中获取子组件传递的数据。示例如下:
<!-- 父组件的.wxml文件 -->
<child-component bind:customEventName="handleChildData"></child-component>
// 父组件的.js文件
Page({
   
  // ...
  handleChildData(event) {
   
    const data = event.detail; // 获取子组件传递的数据
    console.log(data); // 处理子组件传递的数据
  },
});

当子组件调用 sendDataToParent 方法时,将会触发自定义事件 customEventName,并将数据传递给父组件。父组件通过 handleChildData 函数来处理子组件传递的数据。

通过这种方式,子组件就能将数据传递给父组件,实现了子传父的通信。

在微信小程序中,父组件向子组件传递数据可以通过属性传递的方式实现。以下是父传子的通信步骤:

  1. 在父组件中,在使用子组件的地方,通过属性将数据传递给子组件。示例如下:
<!-- 父组件的.wxml文件 -->
<child-component data="{
    {dataFromParent}}"></child-component>
// 父组件的.js文件
Page({
   
  data: {
   
    dataFromParent: 'Hello, child!',  // 要传递给子组件的数据
  },
});
  1. 在子组件中,可以通过 properties 字段定义接收父组件传递数据的属性,并在需要的地方使用该属性。示例如下:
// 子组件的.js文件
Component({
   
  properties: {
   
    data: String,  // 定义接收数据的属性
  },
  // ...
});
<!-- 子组件的.wxml文件 -->
<view>{
  {data}}</view> <!-- 在子组件中使用父组件传递的数据 -->

父组件通过将 dataFromParent 数据传递给子组件的 data 属性,子组件可以接收到父组件传递的数据并在需要的地方使用。

通过这种方式,父组件就能将数据传递给子组件,实现了父传子的通信。

实战

消息通知系统:在一个消息通知系统中,父组件是消息列表,子组件是单个消息。父组件可以向子组件传递需要展示的消息内容,子组件负责展示该消息并提供交互功能(如标记已读)

<!-- 父组件的.wxml文件 -->
<view>
  <message-list messages="{
    {messages}}" bind:markRead="onMarkRead"></message-list>
</view>
// 父组件的.js文件
Page({
   
  data: {
   
    messages: [
      {
   
        id: 1,
        title: "消息标题 1",
        content: "消息内容 1",
        isRead: false
      },
      {
   
        id: 2,
        title: "消息标题 2",
        content: "消息内容 2",
        isRead: false
      }
    ]
  },
  onMarkRead(e) {
   
    const messageId = e.detail;
    // 标记消息为已读
    const messages = this.data.messages.map(item => {
   
      if (item.id === messageId) {
   
        item.isRead = true;
      }
      return item;
    });
    this.setData({
    messages });
    console.log(`已标记消息 ${
     messageId} 为已读`);
  }
});
// 子组件的.js文件
Component({
   
  properties: {
   
    message: Object,
  },
  methods: {
   
    markRead() {
   
      const {
    id } = this.properties.message;
      // 触发标记已读事件
      this.triggerEvent('markRead', id);
    },
  }
});
<!-- 子组件的.wxml文件 -->
<view>
  <view>
    <text>{
  {message.title}}</text>
    <text>{
  {message.content}}</text>
  </view>
  <button wx:if="{
    {!message.isRead}}" bind:tap="markRead">标记已读</button>
</view>

如上,父组件通过属性 messages 将消息列表传递给子组件 message-list。子组件接收到消息后,根据每个消息的内容展示相应的标题和内容,并提供标记已读的按钮。

点击子组件的「标记已读」按钮时,子组件触发 markRead 事件,并将消息的 id 作为参数传递给父组件。父组件接收到事件后,根据消息的 id 更新相应消息的状态为已读。

同时也可以在 onMarkRead 方法中编写处理已读操作的逻辑,例如向后端发送请求更新消息状态。

多层级导航菜单:在一个多层级导航菜单中,父组件是一级菜单,子组件是二级菜单。父组件可以向子组件传递选中的一级菜单项,在子组件中展示对应的二级菜单。

<!-- 父组件的.wxml文件 -->
<view>
  <menu-list menus="{
    {menus}}" bind:selectMenu="onSelectMenu"></menu-list>
</view>
// 父组件的.js文件
Page({
   
  data: {
   
    menus: [
      {
   
        id: 1,
        name: "菜单项 1",
        subMenus: [
          {
   
            id: 11,
            name: "二级菜单项 1-1"
          },
          {
   
            id: 12,
            name: "二级菜单项 1-2"
          }
        ]
      },
      {
   
        id: 2,
        name: "菜单项 2",
        subMenus: [
          {
   
            id: 21,
            name: "二级菜单项 2-1"
          },
          {
   
            id: 22,
            name: "二级菜单项 2-2"
          }
        ]
      }
    ],
    selectedMenuId: null
  },
  onSelectMenu(e) {
   
    const menuId = e.detail;
    this.setData({
    selectedMenuId: menuId });
    console.log(`选中一级菜单 ${
     menuId}`);
  }
});
// 子组件的.js文件
Component({
   
  properties: {
   
    menus: Array
  },
  methods: {
   
    selectSubMenu(e) {
   
      const menuId = e.currentTarget.dataset.menuid;
      // 触发选中菜单事件
      this.triggerEvent("selectMenu", menuId);
    }
  }
});
<!-- 子组件的.wxml文件 -->
<view>
  <view wx:for="{
    {menus}}" wx:key="{
    {index}}" bind:tap="selectSubMenu" data-menuid="{
    {item.id}}">
    <text>{
  {item.name}}</text>
  </view>
</view>

如上,父组件通过属性 menus 将一级菜单传递给子组件 menu-list。子组件接收到菜单后,根据每个菜单项的内容展示菜单名称。

点击子组件的菜单项时,子组件触发 selectMenu 事件,并将菜单的 id 作为参数传递给父组件。父组件接收到事件后,更新选中的一级菜单项。

同时也可以在 onSelectMenu 方法中编写处理菜单选中操作的逻辑,例如根据选中的菜单项加载对应的二级菜单。

电子商务平台:在一个电子商务平台中,父组件是商品列表,子组件是商品卡片。父组件可以向子组件传递商品信息,以便在子组件上展示商品名称、价格等详细信息。

<!-- 父组件的.wxml文件 -->
<view>
  <product-list products="{
    {products}}"></product-list>
</view>
// 父组件的.js文件
Page({
   
  data: {
   
    products: [
      {
   
        id: 1,
        name: "商品 1",
        price: 100,
        image: "image_url_1"
      },
      {
   
        id: 2,
        name: "商品 2",
        price: 200,
        image: "image_url_2"
      }
    ]
  }
});
// 子组件的.js文件
Component({
   
  properties: {
   
    products: Array
  }
});
<!-- 子组件的.wxml文件 -->
<view>
  <view wx:for="{
    {products}}" wx:key="{
    {index}}">
    <image src="{
    {item.image}}"></image>
    <text>{
  {item.name}}</text>
    <text>价格:{
  {item.price}}</text>
  </view>
</view>

如上,父组件通过属性 products 将商品列表传递给子组件 product-list。子组件接收到商品列表后,根据每个商品的信息展示商品名称、价格和图片等详细信息。

也可以根据实际需求,在子组件的模板文件中展示更多的商品信息,比如商品描述、评分等。

表单验证:在一个表单验证页面中,父组件是表单,子组件是各个表单字段。父组件可以将验证规则传递给子组件,子组件根据规则进行实时验证并将验证结果返回给父组件进行整体表单验证。

<!-- 父组件的.wxml文件 -->
<view>
  <form>
    <form-field name="username" label="用户名" rules="{
    {usernameRules}}" bind:validate="onValidate"></form-field>
    <form-field name="password" label="密码" rules="{
    {passwordRules}}" bind:validate="onValidate"></form-field>
    <button bind:tap="submitForm">提交</button>
  </form>
</view>
// 父组件的.js文件
Page({
   
  data: {
   
    usernameRules: [
      {
   
        required: true,
        message: "请输入用户名"
      },
      {
   
        min: 6,
        max: 20,
        message: "用户名长度在6-20个字符之间"
      }
    ],
    passwordRules: [
      {
   
        required: true,
        message: "请输入密码"
      },
      {
   
        min: 8,
        message: "密码长度至少8个字符"
      }
    ]
  },
  onValidate(e) {
   
    const {
    name, valid } = e.detail;
    console.log(`${name} 字段验证结果为: ${valid}`);
    // 根据具体情况处理验证结果,比如更新数据或显示错误提示等
  },
  submitForm() {
   
    // 在这里可以进行整体表单的验证逻辑,根据各字段的验证结果进行处理
    // 若全部字段验证通过,则执行表单提交操作
  }
});
// 子组件的.js文件
Component({
   
  properties: {
   
    name: String,
    label: String,
    rules: Array
  },
  methods: {
   
    validateField(value) {
   
      const rules = this.data.rules;
      let valid = true;
      let message = "";

      for (let i = 0; i < rules.length; i++) {
   
        const rule = rules[i];

        if (rule.required && !value) {
   
          valid = false;
          message = rule.message;
          break;
        }

        if (rule.min && value.length < rule.min) {
   
          valid = false;
          message = rule.message;
          break;
        }

        if (rule.max && value.length > rule.max) {
   
          valid = false;
          message = rule.message;
          break;
        }
      }

      this.triggerEvent("validate", {
    name: this.data.name, valid, message });
    },
    onInput(e) {
   
      const value = e.detail.value;
      this.validateField(value);
    }
  }
});
<!-- 子组件的.wxml文件 -->
<view>
  <text>{
  {label}}</text>
  <input bindinput="onInput"></input>
</view>

如上,父组件定义了两个表单字段的验证规则 usernameRules 和 passwordRules,并将这些规则传递给子组件 form-field。子组件接收到规则后,根据用户输入的值实时进行验证,并将验证结果通过 validate 事件返回给父组件。

父组件可以根据接收到的验证结果进行相应的处理,比如更新数据或显示错误提示等。当用户点击提交按钮时,可以执行整体表单的验证逻辑,根据各字段的验证结果决定是否执行表单提交操作。

视频播放器:在一个视频播放器页面中,父组件是播放器控制条,子组件是视频播放器区域。父组件可以向子组件传递视频播放状态和进度,子组件根据传递的数据进行相应的播放操作。

<!-- 父组件的.wxml文件 -->
<view>
  <video-controls bind:play="playVideo" bind:pause="pauseVideo" bind:seek="seekVideo" bind:timeupdate="updateProgress"></video-controls>
  <video-player src="{
    {videoSrc}}" bind:ended="videoEnded"></video-player>
</view>
// 父组件的.js文件
Page({
   
  data: {
   
    videoSrc: "https://example.com/video.mp4", // 视频地址
    isPlaying: false, // 视频播放状态
    currentTime: 0, // 当前播放时间
    duration: 0, // 视频总时长
  },
  playVideo() {
   
    this.setData({
   
      isPlaying: true
    });
  },
  pauseVideo() {
   
    this.setData({
   
      isPlaying: false
    });
  },
  seekVideo(e) {
   
    const {
    value } = e.detail;
    const videoContext = wx.createVideoContext("videoPlayer");

    videoContext.seek(value);
  },
  updateProgress(e) {
   
    const {
    currentTime, duration } = e.detail;
    this.setData({
   
      currentTime,
      duration
    });
  },
  videoEnded() {
   
    this.setData({
   
      isPlaying: false,
      currentTime: 0
    });
  }
});
// 子组件的.js文件
Component({
   
  properties: {
   
    src: String
  },
  methods: {
   
    onPlay() {
   
      this.triggerEvent("play");
    },
    onPause() {
   
      this.triggerEvent("pause");
    },
    onSeek(e) {
   
      const {
    value } = e.detail;
      this.triggerEvent("seek", {
    value });
    },
    onTimeUpdate(e) {
   
      const {
    currentTime, duration } = e.detail;
      this.triggerEvent("timeupdate", {
    currentTime, duration });
    },
    onEnded() {
   
      this.triggerEvent("ended");
    }
  }
});
<!-- 子组件的.wxml文件 -->
<view>
  <video id="videoPlayer" src="{
    {src}}" bindplay="onPlay" bindpause="onPause" bindseeked="onSeek" bindtimeupdate="onTimeUpdate" bindended="onEnded"></video>
</view>

如上,父组件包含一个视频控制条 video-controls 和一个视频播放器区域 video-player。父组件通过属性绑定将视频地址 videoSrc 传递给子组件。

子组件是一个简单的视频播放器,当用户点击播放按钮时,触发 play 事件,父组件监听该事件并更新播放状态 isPlaying。同理,暂停按钮触发 pause 事件,父组件也进行相应的状态更新。进度条拖动时触发 seek 事件,父组件监听并进行视频进度跳转。

视频播放过程中,子组件会触发 timeupdate 事件,将当前播放时间和视频总时长传递给父组件,父组件通过监听 timeupdate 事件更新播放时间和总时长。当视频播放完成时,子组件触发 ended 事件,父组件重新设置播放状态和当前播放时间。

需要注意的是,示例中使用了微信小程序的视频组件,并通过 wx.createVideoContext 方法获取到视频上下文,从而实现视频跳转操作。

目录
相关文章
|
2月前
|
小程序 JavaScript
【微信小程序】之顶部选项卡自定义tabs(不用mp-tabs扩展组件,太难用了)
【微信小程序】之顶部选项卡自定义tabs(不用mp-tabs扩展组件,太难用了)
|
16天前
|
小程序 数据库
【微信小程序-原生开发】实用教程10 - 动态的新增、修改、删除(含微信云数据库的新增、修改、删除,表单弹窗、确认弹窗、日期选择器、单行输入框、多行输入框、滑动组件的使用)
【微信小程序-原生开发】实用教程10 - 动态的新增、修改、删除(含微信云数据库的新增、修改、删除,表单弹窗、确认弹窗、日期选择器、单行输入框、多行输入框、滑动组件的使用)
14 0
|
16天前
|
小程序
【微信小程序-原生开发】列表 - 拖拽排序(官方组件 movable-area 和 movable-view 的用法)
【微信小程序-原生开发】列表 - 拖拽排序(官方组件 movable-area 和 movable-view 的用法)
17 0
|
16天前
|
小程序 数据库
【微信小程序-原生开发】实用教程15 - 列表的排序、搜索(含云数据库常用查询条件的使用方法,t-search 组件的使用)
【微信小程序-原生开发】实用教程15 - 列表的排序、搜索(含云数据库常用查询条件的使用方法,t-search 组件的使用)
12 0
|
16天前
|
JSON 小程序 数据库
【微信小程序-原生开发】实用教程14 - 列表的分页加载,触底加载更多(含无更多数据的提醒和显示,自定义组件)
【微信小程序-原生开发】实用教程14 - 列表的分页加载,触底加载更多(含无更多数据的提醒和显示,自定义组件)
11 0
|
16天前
|
小程序 JavaScript 前端开发
【微信小程序-原生开发】实用教程06-轮播图、分类页签 tab 、成员列表(含Tdesign升级,切换调试基础库,设置全局样式,配置组件按需注入,添加图片素材,wx:for,生命周期 onLoad)
【微信小程序-原生开发】实用教程06-轮播图、分类页签 tab 、成员列表(含Tdesign升级,切换调试基础库,设置全局样式,配置组件按需注入,添加图片素材,wx:for,生命周期 onLoad)
17 0
|
2月前
|
小程序
微信小程序-其他常用组件
该内容是关于微信小程序组件的介绍,主要包括`button`、`image`和`navigator`。`button`组件比HTML的按钮功能更丰富,通过`open-type`可调用微信功能,如客服、转发等。组件属性包括类型(如`primary`、`warn`)和尺寸(`size`)。`image`组件默认宽300px,高240px,支持设置属性来调整显示效果。`navigator`组件用于页面导航,类似HTML的a标签,常用于页面间的跳转。
27 0
|
2月前
|
小程序
微信小程序-常用的基础内容组件
以下是内容的摘要: 本文介绍了微信小程序中几个重要的组件:text、rich-text和progress。text组件类似于HTML的span标签,用于显示文本,通过selectable属性可实现长按选中文本。rich-text组件能够将HTML字符串渲染成WXML结构,展示富文本内容。progress组件则用于展示进度条,支持不同状态(如成功、警告、等待等)以及自定义颜色和宽度。icon组件则提供了一组预定义的图标,可用于表示各种操作状态或提示信息。
24 0
|
2月前
|
小程序 前端开发 定位技术
微信小程序-常用的视图容器类组件
该内容是关于微信小程序组件的分类和部分具体组件的介绍。主要分为9大类:视图容器、基础内容、表单组件、导航组件、媒体组件、地图组件、画布组件、开放能力和无障碍访问。其中详细讲解了`view`、`scroll-view`、`swiper`及`swiper-item`等组件的用途和示例。`view`用于构建页面布局,`scroll-view`支持滚动效果,`swiper`则用于创建轮播图。此外,还提到了`root-portal`、`page-container`等其他特殊用途的组件。
27 0
|
2月前
|
监控 小程序 前端开发
小程序全栈开发中的WebSocket实时通信实践
【4月更文挑战第12天】本文探讨了小程序全栈开发中WebSocket实时通信的实践,WebSocket作为实现双向实时通信的协议,其长连接特性和双向通信能力在实时聊天、推送、游戏和监控等场景中发挥关键作用。开发者需注意安全性、性能和兼容性问题,以优化用户体验并确保小程序稳定运行。通过掌握WebSocket,开发者能提升小程序的功能性和用户体验。