# 组件结构
# wxml 文件
对于一个自定义组件,我们考虑的是其模板性,也就是不能够将代码写死。因此我们需要在 view 标签里通过调用 js 文件的 data 数据(初始化数据)来进行数据的访问。wx:for="",wx:key="数组中的某个唯一属性"。同时我们需要在 bindtap 属性定义事件绑定函数
wxml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <view class="tabs">
<view class="tabs_title"> <view 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> </view> </view>
|
# wxss 文件
定义了一些类的样式,其中 flex 布局需要重点关注,这对于弹性布局非常重要。
wxss1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| .tabs{} .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; } .tabs_content{}
|
# js 文件
我们需要在 data:{} 中定义我们需要预先定义的数据,然后在 methods:{} 中定义事件的绑定函数,这与页面 js 文件的位置不同(见代码和注释)。然后在 view 标签中定义一个被点击的自定义索引:data-index=""
javascript1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| Component({
properties: { tabs: { type: Array, value: [] } },
data: {
},
methods: { handleItemTap(e) {
const { index } = e.currentTarget.dataset; this.triggerEvent("itemChange", { index }); } } })
|
# json 文件
默认即可
json1 2 3 4
| { "component": true, "usingComponents": {} }
|
# 页面(组件的父组件)结构
# wxml 文件
wxml1 2 3 4 5 6 7 8 9
|
<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:elif="{{tabs[3].isActive}}">3</block> </Tabs>
|
# js 文件
javascript1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| 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 }) } })
|
# json 文件
我们需要在 usingComponents 中找到我们自定义组件的相对路径。注意,由于组件包含了 wxml,wxss,js,json 四个同名文件,因此我们在最后的 Tabs 后不需要添加后缀名。
json1 2 3 4 5
| { "usingComponents": { "Tabs":"../../components/Tabs/Tabs" } }
|
# 过程分析
- 首先我们在 Tabs 组件 wxml 文件中定义一个模板,其中包含了 view 标签和所属的 class 类,用于对应组件 wxss 文件中定义的布局
- 组件的事件回调函数需要定义在 methods 中,在组件 wxml 文件标签中,有这样两个属性:
- bindtap:用于指定点击事件的触发函数名 (handleItemTap)
- data-index:用于指定数据的索引
- 进入组件的 js 文件中,在 methods 中绑定点击事件 handleItemTap (){},在该事件函数中我们首先获取索引,然后触发父组件的自定义事件,同时传递参数给父组件 (this.triggerEvent ("itemChange", { index }))。这里并没有直接对原数组进行修改,因为在组件中对父页面的 data 数据进行修改,是无效的
- 在页面 wxml 文件的 Tabs 自定义组件标签中绑定单击响应函数 (binditemChange="handleItemChange"),然后在页面 js 文件中定义这个函数(与 data 平行,这与组件中函数位置有所不同)。
# 需要注意的地方
- 组件接收父组件的数据位置在 properties 中,需要指定数据名,数据类型和默认 value
- 我们没有将主要的处理步骤放在组件的事件回调函数中,是因为 setData 的时候又将修改过的 tabs 存进了自己的 data 区,也就是说,在 properties 有一个 tabs 数组,在自己的 data 区又有一个 tabs 数组,这会出问题
- 组件 wxml 文件中 slot 标签的作用:一个占位符 插槽,等到父组件调用子组件的时候再传递标签过来,最终这些被传递的标签就会替换 slot 插槽的位置,也就是我们样例中页面 wxml 文件的 wx:if 语句选择的那个标签