前言:组件是放在components文件夹内,页面是放在pages文件夹内,
页面.js 文件中 存放事件回调函数的时候 存放在data同层级下!!!
组件.js 文件中 存放事件回调函数的时候 必须要存在在 methods中!!!
不要搞混
通过一个实例进行讲解
先介绍自定义组件,稍后会涉及父子组件传参
效果图:
组件使用
首先在components文件夹内新建一个文件,例如Tab,用来抽取公共头部,Tab可以像view标签一样被页面使用,即 <Tabs></Tabs>
要求:
子组件:wxml写需要在父组件中展示的内容
页面:在json中先引入子组件,再用标签呈现子组件
具体操作如下:
首先在Tab.wxml写点内容
<view class="tabs">
<view class="tabs_title">
<view
wx:for="{{tabs}}"
wx:key="id"
class="title_item {{item.isActive?'active':''}}"
bindtap="hanldeItemTap"
data-index="{{index}}"
>
{{item.name}}
</view>
</view>
</view>
Tab.js文件,先模拟子组件自己模拟数据并操作
Component({
data: {
tabs: [
{
id: 0,
name: "首页",
isActive: true
},
{
id: 1,
name: "原创",
isActive: false
}
,
{
id: 2,
name: "分类",
isActive: false
}
,
{
id: 3,
name: "关于",
isActive: false
}
]
},
methods: {
hanldeItemTap(e) {
/*
1 绑定点击事件 需要在methods中绑定
2 获取被点击的索引
3 获取原数组
4 对数组循环
1 给每一个循环性 选中属性 改为 false
2 给当前的索引的 项 添加激活选中效果就可以
*/
// 2 获取索引,解构赋值
const { index } = e.currentTarget.dataset;
// 3 获取data中的数组
// 最严谨的做法:重新拷贝一份数组,再对这个数组的备份进行处理,
let tabs=JSON.parse(JSON.stringify(this.data.tabs));
// 4 循环数组
// [].forEach 遍历数组 遍历数组的时候 修改了 v ,也会导致源数组被修改
tabs.forEach((v, i) => i === index ? v.isActive = true : v.isActive = false);
this.setData({
tabs
})
}
}
})
页面使用Tabs自定义组件就很简单
需要在该页面文件夹下的json文件补充以下,记录组件
{
"usingComponents": {
"Tabs":"../../components/Tabs/Tabs"
}
}
wxml
<Tabs></Tabs>
wcss
.tabs_title{
display: flex;
padding: 10rpx 0;
}
.title_item{
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.active{
color:red;
border-bottom: 5rpx solid currentColor;
}
看起来是不是很简单呢
但是,传参呢?
组件传参
现在我们开始做组件传参了!
具体如下:
页面通过标签属性给子组件传参,子组件通过properties接收,子组件通过触发事件向页面传参
页面(父):
-
向子组件传递数据:在子组件的标签(此标签在父组件内),例如
tabs="{{tabs}}"
通过tabs属性传递页面中的定义的tabs数据。 -
接收子组件数据:在子组件的标签(此标签在父组件内即Tabs)上加入一个 自定义事件,注意做好对应关系才能接收数据,用下图可以说明
<Tabs tabs="{{tabs}}" binditemChange="handleItemChange" >
</Tabs>
接收子组件传递过来的数据时,注意要子组件进行传递时的父组件的方法名,也就是说如果子组件用的是itemChange进行传递,那么父组件需要用binditemChange来绑定父组件的方法进行接收。
子组件:
3. 从父接收数据: 子组件下有个properties,把这里面的数据当成是data中的数据直接用即可,里面存放的是从父组件中接收的数据,如下
properties: {
tabs:{
type:Array,
value:[]
}
}
- 向父传递数据:通过自定义事件绑定要传递的数据(例如当前索引index),操作如下
//this.triggerEvent("父组件自定义事件的名称",要传递的参数)
this.triggerEvent("itemChange",{index});
代码实现
父组件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) {
// 接收传递过来的参数
const { index } = e.detail;
let { tabs } = this.data;
tabs.forEach((v, i) => i === index ? v.isActive = true : v.isActive = false);
this.setData({
tabs
})
}
})
父组件wxml
<Tabs tabs="{{tabs}}" binditemChange="handleItemChange" >
</Tabs>
子组件wxml
<view class="tabs">
<view class="tabs_title">
<view
wx:for="{{tabs}}"
wx:key="id"
class="title_item {{item.isActive?'active':''}}"
bindtap="hanldeItemTap"
data-index="{{index}}"
>
{{item.name}}
</view>
</view>
</view>
子组件js
// components/Tabs.js
Component({
properties: {
tabs:{
type:Array,
value:[]
}
},
data: {
},
methods: {
hanldeItemTap(e){
const {index}=e.currentTarget.dataset;
// 5 触发父组件中的自定义事件 同时传递数据给
this.triggerEvent("itemsChange",{index});
}
}
})
至此,我们就完成了自定义组件的使用和传参啦
总结一下内容!!
父组件要使用子组件的话,首先在json中引入,然后在页面中用子组件标签<子组件名></子组件名>
父组件向子组件传参通过自己页面内的子标签传递,通过子组件的传递的方法名进行绑定接收的方法
子组件向父组件传参通过绑定方法传递,通过properties进行接收。
还有一个点,如果将父组件的写在子组件标签内容的元素显示出来呢,这时候就用到slot
slot插槽
slot 标签 其实就是一个占位符 插槽,写在子组件内用来接收父组件通过标签传递过来的
等到父组件调用子组件的时候,再传递标签过来最终这些被传递的标签,就会替换 slot 插槽的位置
子组件wxml,增加一个slot
<view class="tabs">
<view class="tabs_title">
<view
wx:for="{{tabs}}"
wx:key="id"
class="title_item {{item.isActive?'active':''}}"
bindtap="hanldeItemTap"
data-index="{{index}}"
>
{{item.name}}
</view>
</view>
<view class="tabs_content">
<slot></slot>
</view>
</view>
父组件wxml,block就是要传递给子组件的内容,会替换slot
<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>
至此,完成小案例啦!你也快去试试吧!