阅读 2721

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

前言

做微信小程序开发也有一年半之久了,很惭愧,期间很少用到小程序的自定义组件,最近才开始认真研究了一下,之前都是用模板来展示与封装样式。毫无疑问,比起自定义组件就是有很多的不足,最大的缺点就是不能封装js,即便有事件,也只能将它定义在Page中。

相信很多同学在研究自定义组件的时候也产生很多困惑,不知从何下手。废话不多说,这里分享一下微信小程序父子组件间如何通信。

代码

新建一个小程序项目,目录结构如下,(index页面,作为首页;components文件夹存放组件,在里面建parent父组件和child子组件)。


小程序的自定义组件需要在对应的json文件中说明为组件,即parent.json 和 child.json 的代码如下:

{
  "component":true
}复制代码

对应这两个js文件也要写为Component构造函数:

Component({

})复制代码


在index.wxml使用和组件如下,并且需要在其index.json中声明组件的引用:

<!--index/index.wxml-->
<view>
  <parent>
    <child>
      <view>index.html的内容</view>
    </child>
  </parent>
</view>复制代码
{
  "usingComponents": {
    "parent": "/components/parent",
    "child": "/components/child"    
  }
}复制代码


下面将两个组件的全部代码贴上:

parent:

<!--components/parent.wxml-->
<view>
  我是parent的内容 {{parentProps}}
  <button catchtap="parentClick">parent按钮</button>
  <slot />
</view>复制代码
// components/parent.js
Component({
  relations: {
    './child': {
      type: 'child', // 关联的目标节点应为子节点
      linked: function (target) {
        // 每次有custom-li被插入时执行,target是该节点实例对象,触发在该节点attached生命周期之后
      },
      linkChanged: function (target) {
        // 每次有custom-li被移动后执行,target是该节点实例对象,触发在该节点moved生命周期之后
      },
      unlinked: function (target) {
        // 每次有custom-li被移除时执行,target是该节点实例对象,触发在该节点detached生命周期之后
      }
    }
  },
  methods:{
    parentClick(){
      var child = this.getRelationNodes('./child')
      child[0].setData({
        childProps:'hello child'
      })
    }
  }
})复制代码

child:

<!--components/child.wxml-->
<view style='padding:40rpx 0;text-align:center;'>------------分割线---------------</view>
<view>
  我是child的内容 {{childProps}}
  <button catchtap="childClick">child按钮</button>
  <slot />
</view>复制代码
// components/child.js
Component({
  relations: {
    './parent': {
      type: 'parent', // 关联的目标节点应为子节点
      linked: function (target) {
        // 每次有custom-li被插入时执行,target是该节点实例对象,触发在该节点attached生命周期之后
      },
      linkChanged: function (target) {
        // 每次有custom-li被移动后执行,target是该节点实例对象,触发在该节点moved生命周期之后
      },
      unlinked: function (target) {
        // 每次有custom-li被移除时执行,target是该节点实例对象,触发在该节点detached生命周期之后
      }
    }
  },
  methods:{
    childClick() {
      var parent = this.getRelationNodes('./parent')
      parent[0].setData({
        parentProps: 'hello parent'
      })
    }
  }
})复制代码


微信开发工具编译后,效果如下:

wxml中的是插槽,用于承载组件引用时提供的子节点。

这里做一下说明,parent和child组件分别要在对应的component函数中用relations字段进行关联,官方文档是这样说的:



地址:developers.weixin.qq.com/miniprogram…

重点是parent组件怎么将数据传给child,或者child组件怎么将数据传给parent,同样官方文档中有一句话如下,但是没有具体示例:


这里的custom-li对应本文的是child组件,也就说说通过getRelationNodes方法可以拿到组件已经关联了的节点,这就好办了,拿到对应的节点就可以调用setData方法设置关联节点的属性值,即nodes.setData({}),这样就达到了父子组件通信的目的,对应本文,点击页面中的按钮,可以将parent组件的"hello child"传给child,或者将child组件的"hello parent"传给parent,效果如下:

组件间的关系有四个值:parentchildancestor(祖先节点)descendant(子孙节点)。

经试验,parent和child、ancestor和descendant是一起使用的,交叉使用无效。

至于同级组件如何通信,好像就无能为力了,官方文档也没有说明,所以在封装自定义组件的时候应避免写成同级组件。

关于behaviors

behaviors一开始误以为也和组件通信有关,但这个貌似就是用于代码共享。

最后

想说的是从事小程序开发中,还是学到很多东西的,有时候,也因为它新,并且有些东西一开始并不完善,所以网上也找没有答案,只能自己尝试和摸索,所以打算写一系列小程序的文章,记录一下遇到的坑及分享一些自己的小程序开发经验,也算是给这一年半的一个总结。