自定义组件算是在学习微信程序开发过程中遇到的一个难点,首先我们需要明确我们为什么要使用自定义组件,在微信小程序中有很多提供的官方组件比如,
view
,text
,image
等等,这些组件方便我们开发使用,因为我们会频繁使用这些组件来完成我们开发工作。所以我们自定义组件也是这个样子的,程序开发过程中存在许多相似的模块开发,我们可以在遇到每一个模块都进行一遍设计,但是这样的代码太过臃肿,不利于维护,所以就通过自定义组件,在需要的时候直接调用,代码更加简洁高效。接下来就一起看看我们是怎么自定义组件的吧。
1.创建自定义组件
我们首先在小程序文件夹目录下新建一个component文件夹,在component文件夹下新建一个自定义组件文件夹,我们自定义组件叫Tabs,我们将这个命名文件夹,随后右键选择新建Component,名字命名Tabs,开发者工具就帮我们建立四个文件。json
wxml
wxss
js
2.声明组件
创建好了组件文件目录,我们需要声明组件,在Tbs.json
中进行自定义组件声明
{
"component": true,
"usingComponents": {}
}
3.编辑组件
我们需要在wxml 文件中编写组件,在wxss 文件中编写组件样式
【Tabs.wxml】
<view class="tabs">
<view class="tabs_title">
<view class="title_item active" >首页</view>
<view class="title_item">原创</view>
<view class="title_item">分类</view>
<view class="title_item">关于</view>
<view
</view>
【Tabs.wxss】
.tabs{}
.tabs_title{
display: flex;
padding: 10rpx;
}
.title_item{
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.active{
color: red;
border-bottom: 10rpx solid currentColor;
}
.tabs_content{}
4.调用组件
我们自定义组件定义好了,我们需要去调用,首先我们需要在需要的应用处声明引入组件,我们在我们demo16下引入组件,我们首先在demo16.json中进行如下引入声明
{
"usingComponents": {
"Tabs":"../../components/Tabs/Tabs"
}
}
然后在demo16.wxml中引入就可以了
<Tabs ></Tabs>
以上就可以完成一个基本的自定义组件,但是我们还想更多有趣的玩法操作呢?
首先我们现在用的自定义组件数据全部来自,Tabs,我们希望的是数据由父组件(demo16)传向子组件(Tabs),这样设计也更加灵活,同时子组件也可以向父组件传递信息,完成信息的交互。
5.自定义组件传参
【demo-wxml】
<Tabs tabs="{{tabs}}" binditemChange="handleItemChange" >
<block wx:if="{{tabs[0].isActive}}">0</block>
<block wx:elif="{{tabs[1].isActive}}">1</block>
<block wx:elif="{{tabs[2].isActive}}">2</block>
<block wx:else>3</block>
</Tabs>
【demo-js】
// pages/demo16/demo16.js
Page({
/**
* 页面的初始数据
*/
data: {
tabs:[
{
id:0,
name:"首页",
isActive:true
},
{
id:1,
name:"原创",
isActive:false
},
{
id:2,
name:"分类",
isActive:false
},
{
id:3,
name:"关于",
isActive:false
}
]
},
//自定义组件
handleItemChange(e){
//console.log(e);
//接收参数
const{index} =e.detail;
//console.log(index)
let {tabs} = this.data;
console.log(tabs)
//循环处理
tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
this.setData({
tabs
})
}
})
通过以上代码我们可以看到我们在demo.js中的data中定义了数据,数据名tabs,类型是一个列表。通过自定义组件属性的方式将参数进行传递,那么接下来就是子组件对参数的接收。
【Tabs-JavaScript】
// components/Tabs/Tabs.js
Component({
/**
* 里面存放的是,要从父组件接收的数据
*
*/
properties: {
// //要接受数据的名称
// aaa:{
// //type 要接受的数据类型
// type:String,
// //value 默认值
// value:""
// }
tabs:{
type:Array,
value:[]
}
},
/**
* 组件的初始数据
*/
data: {
},
/**
1.页面.js文件中 存放事件回调函数的时候 存放在data同层级下的
2.组件.js文件中 存放事件回调函数的时候必须要存在methods中
*/
methods: {
handleItemTap(e){
/*
1.绑定点击事件,需要在methods中绑定
2.获取被点击的索引
3.获取原数组
对数组循环
1.给每一个循环性选中的属性改为false
2.给当前的索引的项添加激活选中效果就可以了
4.点击触发事件
触发父组件中的自定义事件 同时传递数据给父组件
this.triggerEvent("父组件中自定义事件名称",要传递的参数)
*/
console.log(e)
//获取索引
const {index}=e.currentTarget.dataset;
this.triggerEvent("itemChange",{index});
//获取data中数组
//let {tabs} = this.data;
//循环处理
//tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
// this.setData({
// tabs
// })
}
}
})
子组件接收父组件的参数是在 JavaScript文件下的Component里面properties中接收,接收格式就是数据名称,数据类型还有默认值,接收道德数据和本身定义在data下的数据使用方式一样{{tabs}}
即可。我们在程序中设定了一个点击的绑定事件,通过点击不同值,产生不同点击内容与显示效果。
【Tabs-wxml】
<view class="tabs">
wx:for="{{tabs}}"
wx:key="id"
class="title_item {{item.isActive? 'active':''}}"
bindtap="handleItemTap"
data-index="{{index}}"
>
{{item.name}}
</view>
<!-- </view> -->
<view class="tabs_content">
<!-- slot 标签 只是一个占位符 插槽
等到 父组件调用子组件的时候 再传递 标签过来 最终这些被传递的标签就会替换slot插槽位置
-->
<slot></slot>
</view>
</view>
我们希望将点击这件事的参数传回给父组件,通过this.triggerEvent("父组件中自定义事件名称",要传递的参数)
,进行传递,父组件中的事件进行接收binditemChange="handleItemChange"
,我们这里传递回去的是index,在父组件的回调函数中进行处理详情见【demo-js】,这样就完成了数据的传递。我们希望在点击不同的按钮显示不同的内容,我们使用wx:if判断,在子组件中我们用slot标签即可,这是一个占位符,等到 父组件调用子组件的时候 再传递 标签过来 最终这些被传递的标签就会替换slot插槽位置。回到【demo.wxml】,我们可以看到在Tabs中间定义的就是父组件要传递过来的数据。
由此我们完成了自定义组件的实验,并且实现了父组件,子组件的数据传递。我们看看结果吧。
可以看到,我们在点击分类的时候,分类效果处于激活状态,同时查看Tabs数据,看到tabs[2]
的isActive是true,其他为false,实现类我们想要的功能。
6.小结
- 父组件通过属性向子组件传递参数,子组件通过propertie接收参数
- 子组件通过事件向父组件传递参数
- 父组件监听
handleItemChange
事件. - 子组件通过
itemChange
事件触发父组件binditemChange
自定义组件触发事件时,需要使用triggerEvent("父组件中自定义事件名称",要传递的参数)
进行参数传递。