小程序组件和页面的通信 ★

很多情况下,组件内展示的内容(数据、样式、标签)并不是在组件内写死的,而且由使用者(引用组件的页面)来决定,这样就可以做到类似于 vue 的父子组件传值,组件还可以定义自定义事件向页面发送信息,示意图如下:

1、向组件传递数据 — properties

大部分情况下,组件只负责布局和样式,内容是由使用组件的对象来决定,所以,我们经常需要从外部传递数据给组件,让组件来进行展示。向组件传递数据 — 使用 properties 属性:

<!--components/my-prop/my-prop.wxml-->
<view class='title'>{{title}}</view>        <!--title的值是页面传过来的/或默认的-->
<view class='content'>我是组件的内容/view>

<!--components/my-prop/my-prop.js-->
Component({
    properties:{           <!--组件的Component构造器内的properties属性用来接受页面传给组件的值-->
        //title:String,
        title:{            <!--推荐这样写,因为有默认值-->
            type:String,
            value:'默认犬种'
        },
        observer:function(neVal,oldVal){   <!--检测跟踪页面传递过来的新值,和组件的默认值--> 
            console.log(newVal,oldVal);
        }
    },
    data:{}
    methods:{}
})

<!--引用my-prop组件的home.wxml页面-->
<my-prop title = "柴犬"/>        <!--页面将title传递给组件-->
<my-prop title = "二哈"/>
<my-prop/>                       <!--页面如果不传值给组件,将显示默认值-->

2、向组件传递样式 — externalClasses

有时候,我们不希望将样式在组件内固定不变,而是外部可以决定样式,这个时候,我们可以使用 externalClasses 属性:(1)在 Component 对象中,定义 externalClasses 属性(2)在组件内的 wxml 中使用 externalClasses 属性中的 class(3)在页面中传入对应的 class,并且给这个 class 设置样式。

<!--components/my-prop/my-prop.wxml-->
<view class='title titleclass'>我是组件</view>    <!--titleclass类名的值是页面传过来的-->
<view class='content'>我是组件的内容/view>

<!--components/my-prop/my-prop.js-->
Component({
    properties:{},
    externalClasses:['titleclass'],   <!--组件的Component构造器内的externalClasses属性用来接受页面传给组件的样式值-->
    data:{}
    methods:{}
})

<!--引用my-prop组件的home.wxml页面-->
<my-prop titleclass="red"/>      <!--页面将titleclass传递给组件-->
<my-prop titleclass="blue"/>     <!--titleclass属性的值即为home.wxss中定义的.red类名样式-->
<my-prop titleclass="green"/>    <!--这里实际可以理解为将页面定义的wxss类名样式直接传递给组件-->

3、组件向外传递事件 — 自定义事件

有时候是自定义组件内部发生了事件,需要告知使用者(引用组件的页面),这个时候可以使用自定义事件:(1)监听组件的点击,为其绑定点击函数(2)在组件的 js 文件定义点击函数,并通过:this.triggerEvent('increment',{name:'erha'},{}); 的方式向外传递事件(3)在页面的的组件占位符上对组件发射出来的事件进行监听,并在页面的 js 文件对鉴定事件进行定义(4)在页面的 js 文件中可以通过 event 参数拿到组件传递过来的 payload 参数。

<!--components/my-event/my-event.wxml-->
<button size='mini' bind:tap="handleIncrement">+1</button>

<!--components/my-event/my-event.js-->
Component({
    methods:{
        handleIncrement(){
            this.triggerEvent('increment',{name:'erha'},{});    <!--第二个参数是payload载荷-->
        }
    }
})

<!--引用my-event组件的home.wxml页面-->
<my-event bind:increment="handleIncrement"/>

<!--引用my-event组件的home.js文件-->
Page({
    data:{
        counter:0;
    }, 
    handleIncrement(event){
        console.log(event);    <!--通过event对象内的detail可以拿到子组件传递过来的payload参数-->
        this.setData({
            counter: this.data.counter + 1;
        })
    }
})

4、页面直接调用组件修改数据/方法 — this.selectComponent

在页面或者别的组件中,可以通过 selectComponent() 方法获取指定的 id 或 class 的组件对象(推荐使用 id 的方式),然后通过该组件对象即可直接调用该组件内的数据和方法,不推荐直接修改组件中的数据,而是调用组件内的方法修改组件内的数据。

<!--components/my-sel/my-sel.wxml-->            <!--components/my-sel/my-sel.json-->
<view>组件内的计数:{{counter}}</view>            {
<!--components/my-sel/my-sel.js-->                   "components":true;
Component({                                      }
    data:{ counter:0 },
    methods:{ increment(num){ this.setData({counter:this.data.counter + num}) }
})
-----------------------------------------------------------------------------------------------------------------
<!--pages/home/home.wxml-->
<my-sel id="sel-id" class="sel-class"/>    <!--直接选中组件修改数据/调用方法-->
<button size='mini' bind:tap="handleEncrementcpnt">修改组件内的数据</button>

<!--pages/home/home.js-->                         <!--pages/home/home.json-->
Page({                                            "usingComponents":{ "my-sel":"/components/my-sel/my-sel" }
    handleIncrementCpn(){
        <!--最终目的:修改my-sel中的counter-->
        const my_sel_class = this.selectComponent('.sel-class');<!--通过class拿到组件-->
        const my_sel_id = this.selectComponent('#sel-id');      <!--通过id拿到组件,推荐这种id方式-->
        <!--组件对象.setData(),这种可以达到目的,但是不推荐这样直接修改组件中的data-->
        my_sel_id.setData({
            counter: my_sel.data.counter + 20;
        })
        <!--通过方法对数据进行修改-->
        my_sel_id.increment(10);
    }
})

5、组件的插槽 — slot

5.1、slot 插槽的定义:在生活中很多地方都有插槽,电脑的 USB 插槽,插板当中的电源插槽。插槽的目的是让原来的设备具备更多的扩展性,比如电脑的 USB 插槽就可以插入U盘、硬盘、手机、音响、键盘、鼠标等等。组件的 slot 插槽也是为了让我们封装的组件更加具有扩展性,使用者可以决定组件内部的一些内容到底展示什么。

5.2、单个插槽的使用

除了组件的内容和样式可能由外界决定之外,显示的方式也可由外界决定,比如一个组件定义了头部和尾部,但是中间的内容可能是一段文字,也可能是一张图片,或者是一个进度条。在不确定外界想插入什么的前提下,我们可以在组件内预留 slot 插槽。

<!--components/my-slot/my-slot.wxml-->                        <!--components/my-slot/my-slot.json-->
<view>组件头部</view>                                          {
<slot></slot>        <!--可以是单标签,也可以是双标签-->             "components":true;
<view>组件尾部</view>                                          }
-----------------------------------------------------------------------------------------------------------------
<!--pages/home/home.json-->
"usingComponents":{ "my-slot":"/components/my-slot/my-slot" }

<!--pages/home/home.wxml-->
<my-slot><button size='mini'>插槽按钮</button></my-slot>     <!--页面显示:组件头部、插槽按钮、组件尾部-->
<my-slot><slider value='60'></slider></my-slot>             <!--页面显示:组件头部、slider滑块、组件尾部-->

5.3、多个插槽的使用

有时候为了让组件更加灵活,需要定义多个插槽,为了区分它们,需要给每一个组件 name 属性,而且还必须在组件的 Component 对象中添加一个选项:options:{ multipleSlots:true }。

<!--components/my-slots/my-slots.wxml-->                        <!--components/my-slots/my-slots.json-->
<view>组件头部</view>                                            {
<view class='slot1'><slot name="slot1"/></view>                      "components":true;
<view class='slot2'><slot name="slot2"/></view>                 }
<view class='slot3'><slot name="slot3"/></view>                 <!--components/my-slots/my-slots.js-->
<view>组件尾部</view>                                            Component({
                                                                    options:{
                                                                        multipleSlots:true
                                                                    }
                                                                })
-----------------------------------------------------------------------------------------------------------------
<!--pages/home/home.json-->
"usingComponents":{ "my-slots":"/components/my-slots/my-slots" }

<!--pages/home/home.wxml-->
<my-slots>
    <button size='mini' slot="slot2">插槽按钮</button>
</my-slots>

6、自定义组件练习 — tab-control

需求:开发一个 tabcontrol 自定义控制导航组件,如下图所示,为了提高该组件的复用性,要求导航中的文字不能在组件中写死,而是由外界页面传递进去的,而且在点击该组件时需要向外界发送自定义事件,告知外界页面导航中的哪个模块被点击了。

开发前准备:需要在根目录下新建 components\tab-control 组件,tab-control 组件的 json 文件中,有一个 "component":true 标识,只有加上这行代码,当前的文件夹才是一个组件。然后到 home.json 文件中对该组件进行注册:{"usingComponents":{"tab-control":/component/tab-control/tab-control}},然后再到 home.wxml 通过 <tab-control> 标签对其进行引用。

<!--components/tab-control/tab-control.wxml-->
<view class='tab-control'>
  <block wx:for="{{titles}}" wx:key="{{index}}">
    <view class='tab-item {{currentIndex==index ? "active" : ""}}' bindtap="handleItemClick" data-index="index">
      <text>{{item}}</text>
    </view>
  </block>
</view>
<!--components/tab-control/tab-control.wxss-->
.tab-control{              .tab-item{                .active{         .active text{
    display:flex;              flex:1;                   color:red;       border-bottom:6rpx solid red;
    height:88rpx;              text-align:center;    }                    padding:26rpx 16rpx;
    line-height:88rpx;     }                                          }
}
<!--components/tab-control/tab-control.js-->              <!--components/tab-control/tab-control.json-->
Component({                                               {
    properties:{  <!--接收home.wxml中传递过来的值-->            "component":true
        titles:{                                          }
            type:Array,
            value:[]
        }
    },
    data:{ currentIndex:0 }
    methods:{
        handleItemclick(event){
            const index = event.currentTarget.dataset.index;    <!--取出index -->
            this.setData({ currentIndex:index; });              <!--修改currentIndex-->
            <!--通知页面内部的点击事件-->
            this.triggerEvent('itemclick',{index,title:this.properties.titles[index]},{});
        }
    }
}
-----------------------------------------------------------------------------------------------------------------
<!--pages/home/home.json-->
"usingComponents":{ "tab-control":"/components/tab-control/tab-control" }
<!--pages/home/home.wxml-->
<tab-control titles="{{['衣服','裤子','鞋子']}}" bind:itemclick="handleTabClick"/>
<!--pages/home/home.js-->
Page({
    handleTabClick(event){
        console.log(event);    <!--通过event对象内的detail可以拿到子组件传递过来的payload参数-->
    }
})
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值