文章目录
- 前言
- 一、组件通信
- 1.微信小程序组件内部(页面与逻辑层之间)通信
- 2.微信小程序组件之间(父子组件)通信
- (1)父组件是如何向子组件传递数据的
- (2)子组件是如何向父组件传递数据的
- 二、page页面之间的通信
- 1. a页面 向 b页面 携带数据跳转
- 2. b页面获取 a页面传递过来的数据
前言
今天我们来说下微信小程序的两种通信:
微信小程序通过数据绑定和事件系统进行组件之间的通信。
微信小程序通过url页面导航进行页面之间的通信。
一、组件通信
1.微信小程序组件内部(页面与逻辑层之间)通信
(1)页面是获取逻辑层数据
页面是通过数据绑定的方式获取逻辑层数据的,我们来看下页面是如何获取逻辑层的数据,在页面 .wxml 中有如下代码,这是一个轮播图的实现代码:
<view class="detail_swiper"><swiper autoplay circular indicator-dots><swiper-itemwx:for="{{pics}}"wx:key="pics_id"><image mode="widthFix" src="{{item.pics_mid}}"></image></swiper-item></swiper>
</view>
其中 pics是从逻辑层 .js 中获取的变量,pics是一个数组是用来存放轮播图需要的图片地址的
Page({/*** 页面的初始数据*/data: {//tab标题数据pics:[{pics_id:0,pics_mid:"https://.....1.jpg"},{pics_id:1,pics_mid:"https://.....2.jpg"},{pics_id:2,pics_mid:"https://.....3.jpg"}]},
})
这里需要说明一下,微信小程序大小的限制:
1.不限制分包的数量;
2.所有分包的大小不能超过20m;
3.单个包的大小不能超过2m;
当前微信小程序大小限制以及为什么要限制大小:
因为小程序的设计初衷就是用完即走,轻量化应用。不建议将它当成一个app来设计,所以考虑到启动速度等方面所以才对大小做了限制。
因为小程序有包大小限制,而图片本身就很大,所以小程序的图片最好是使用网络图片。
回到刚刚的代码,pics这个数组被绑定到了页面的标签上,标签通过wx:for 循环 将 pics作为循环数据。
在pics使用的过程中,如果pics的值发生了变化,就要将新数据重新绑定到该变量中,写法如下:
this.setData({pics:pics
})
(2)页面向逻辑层传递数据
页面是通过事件绑定向逻辑层传递数据的,我们来看下页面.wxml是如何向逻辑层.js传递参数的,在上述(1)代码中,我们已经实现了轮播图。这时候想在图片轮播的时候点击各个图片,实现图片的大图预览页面,那就需要当我们点击其中一个轮播图片时,需要将点击的是第几张图片这个参数传递给逻辑层.js层进行处理,实现如下:
<view class="detail_swiper"><swiper autoplay circular indicator-dots><swiper-itemwx:for="{{pics}}"wx:key="pics_id"bindtap="handlePreviewImage"data-url="{{item.pics_mid}}"><image mode="widthFix" src="{{item.pics_mid}}"></image></swiper-item></swiper>
</view>
可以看到这里我们给轮播图子项绑定了handlePreviewImage这个点击事件:bindtap="handlePreviewImage"
我们这个时候通过 data- 来存放我们需要传递的数据,这里传递点击图片的url:data-url="{{item.pics_mid}}"
,
data- 是自定义的值:
因为微信小程序中不能直接使用函数传参,就是用data-来绑定一个属性,进行传参。也就是说微信小程序没有有以下传参形式:
bindtap="handlePreviewImage(item.pics_mid)"
当我们将这个图片的url地址传递给.js逻辑层之后,在逻辑层通过handlePreviewImage进行参数的接收:
//点击轮播图放大预览事件handlePreviewImage(e){//1构造图片预览的图片数组const urls = this.pics.map(v=>v.pics_mid);//2接收传递过来图片的urlconst current = e.currentTarget.dataset.urlwx.previewImage({ //解构赋值 相当于 //current:current ,urls:urlscurrent,urls,})},
可以看到刚刚我们传递的参数是通过e.currentTarget.dataset.url
进行接收的,为什么要这样写?这个e是我们在页面.wxml传递过来的事件源,我们传递的参数也包含在内,而这个参数就存放在e.currentTarget.dataset.url里面,具体 的数据结构可以自行通过:console.log(e)
来打印观察。这里的wx.previewImage
是微信的图片预览组件,具体用法详见微信小程序的api文档
。
由以上可知 监听事件 的相关结论:
1、事件是视图层到逻辑层的通讯方式
2、事件可以将用户的行为反馈到逻辑层进行处理
3、事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数
4、事件对象可以携带额外信息,如 id, dataset, touches
2.微信小程序组件之间(父子组件)通信
上一节有关 2、微信小程序-组件
中简单提到过自定义组件的构建和使用,这节就通过自定义组件来具体说说组件之间是如何进行通信的。
为什么要自定义组件:
1、小程序自定义组件,开发者可以将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用
2、复杂的页面拆分成多个低耦合的模块,有助于代码维护,自定义组件在使用时与基础组件非常相似,使用方便。
首先我们将某个功能转化为自定义的组件,这个单独的组件我们在这里称之为子组件
而我们在将页面里引入这个子组件,引入的组件我们称之为父组件
接下来我们就来具体看下自定义的通信:
(1)父组件是如何向子组件传递数据的
父组件向子组件传递数据是通过自定义属性的方式实现的。下面是我们自定义的组件 Tabs ,用于展示tab点击切换页面。
<Tabs tabs="{{tabs}}" binditemChange="handleItemChange" >
</Tabs>
这个{{tabs}}我们通过上面页面与逻辑层的通信分析可以知道,这个是通过数据绑定获取到的逻辑层.js的数据。而 tabs=
,这个参数是什么呢?
tabs=
就是我们要说的 父组件向子组件传递数据是通过自定义属性的方式实现的,通过自定义的属性tabs。
当我们传入这个数据,子组件是如何接收的呢?
在这之前我们先来了解下自定义组件的内部构造:
在子组件内,不是通过page而是Component构造器来定义组件的。调用Component构造器时,可以指定组件的属性,数据,方法等。注意要区分这两个属性:
1、properties对象:接收父组件传过来的自定义属性数据,可以是对象,数组,基本数据类型等
2、data对象:是定义当前组件内的私有变量数据,可用于组件模板的渲染
//这里的不再是 Page 而是 Component
Component({/*** 组件的属性列表,存放的是要从父组件中接收的数据*/properties: {tabs:{//type 要接收数据的类型type:Array,//value 默认值value:[]}},/*** 组件的自定义初始数据*/data: {},
})
上述代码中properties属性中的tabs变量,就是用来存放我们刚刚父组件传递过来的tabs数据的。这里需要定义tabs的数据类型和默认值。
(2)子组件是如何向父组件传递数据的
父组件想要拿到子组件的数据,通过在组件上绑定自定义监听事件。
1、父组件拿到子组件传递过来数据的处理
首先父组件需要有监听自定义组件事件的方法,这个与监听基础组件事件的方法完全一致,就是通过 binditemChange="handleItemChange"
绑定 binditemChange事件来获取子组件的数据的。
<Tabs tabs="{{tabs}}" binditemChange="handleItemChange">
通过方法handleItemChange
来获取到数据,这个数据就是子组件点击 tab的引索 index
,通过 e.detail
获取,具体为什么同样可以使用 console.log(e)
打印的方式印证
handleItemChange (e) {//获取被点击标题的索引const {index} = e.detail;},
2、子组件通过触发事件的方式向父组件传递数据
通过1、的分析是、在父组件中通过监听自定义事件也就是拿到子组件传递过来数据的处理,子组件通过事件绑定首先传入需要向父组件传递的数据 data-index="{{index}}"
:
首先子组件得有点击触发的事件:
<view wx:for="{{tabs}}" wx:key="id" bindtap="handleItemTab"data-index="{{index}}">{{item.value}}</view>
这里我们可以看到子组件我们绑定了事件 binditemChange="handleItemChange"
:还记得组件内部的方法是定义在与data同层级下的,而自定义组件的方法是放在method对象里的,进入handleItemTab
方法
methods: {handleItemTab(e){//解构其实就是对复杂类型进行解构的时候,复制了一份变量的引用,将对象中的key属性转成自定义的属性const {index} = e.currentTarget.dataset//5 触发父组件点击事件this.triggerEvent("itemChange",{index})}
}
关键代码就是
this.triggerEvent(“itemChange”,{index})
这就是子组件触发父组件点击事件的方法,需要使用 triggerEvent
方法,triggerEvent
方法指定事件名、detail对象和事件选项,
{index}
,是我们在detail对象中传入我们要向父组件传递的数据 ;
itemChange
,是我们要指定的触发父组件事件的方法名;
回到父组件
<Tabs tabs="{{tabs}}" binditemChange="handleItemChange">
通过子组件的triggerEvent
方法,我们得到了要触发的事件,将其绑定到父组件上
bind:itemChange=“handleItemChange”
也可以写成 binditemChange="handleItemChange"
以上就是子组件向父组件传递数据的全部过程。
小结:
1、父组件传递数据给子组件:因为小程序当中数据的传递是单向的,也就是父组件传递数据给子组件,是通过在组件上添加自定义属性实现的,而在子组件内部的properties中接收自定义组件的属性。
2、子组件传递数据给父组件:它是通过在引用组件上绑定监听自定义事件,然后在子组件的事件方法内,通过this.triggerEvent方法进行触发自定义事件名,并可以携带子组件内的数据,在父组件中的函数中可以通过event.detail可以拿到子组件中传递给父组件的值,从而重新在setData数据,就可以更新父组件中的初始化数据。
二、page页面之间的通信
我们知道页面之间的跳转可以通过路由组件来实现,其中组件的属性url就是要跳转到页面的路径。
1. a页面 向 b页面 携带数据跳转
代码如下:
<navigator class="goods_item"wx:for="{{goodsList}}"wx:key="goods_id"url="/pages/good-detail/index?goods_id={{item.goods_id}}"></navigator>
比如现在有个商品列表页面,我们点击列表中的一个商品可以跳转到商品的详情页面,这时跳转到商品详情页面就要携带商品的id,怎么样传递的呢? 可以看到 url
url=“/pages/good-detail/index?goods_id={{item.goods_id}}” 属性参数是通过 ?goods_id={{item.goods_id}}
将 item.goods_id
2. b页面获取 a页面传递过来的数据
当跳转b的商品详情页面,我们在微信开发者工具中也可以观察到这个传过来的id 数据,打开左下角的页面参数:
此时可以看到商品详情页面已经获取到 goods_id
,既然获取到了,我们在代码里怎么获得呢?
打开b页码也就是商品详情页面的逻辑层.js ,我们知道初始化页面的时候就会回调小程序的生命周期函数onLoad
,我们就在这里面获取参数,代码如下:
onLoad: function (options) {const {goods_id} = options;},