抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

Hello world!

自定义组件

Component(Object object) | 微信开放文档 (qq.com)

将部分重复代码抽取出来

商品分类 (taobao.com)

创建自定义组件

类似于页面,一个自定义组件由json、wxml、wxss、js 4个文件组成

可以在微信开发者⼯具中快速创建组件的⽂件结构

image-20210718102246185

声明组件、引入组件

tabs.json

1
2
3
{
"component": true
}

demo01.json

1
2
3
4
5
{
"usingComponents": {
"Tabs": "/components/Tabs/Tabs"
}
}

简单编辑组件

Tabs.wxml

1
2
3
4
5
6
7
8
9
10
11
12
<!--components/Tabs/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 class="tabs_content">

</view>
</view>

Tabs.wxss

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* components/Tabs/Tabs.wxss */
.tabs {}

.tabs_title {
display: flex;
padding: 10rpx 0;
}

.title_item {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}

/* 选中时的样式 */
.active {
color: #b81d24;
border-bottom: 5rpx solid currentColor;
}

.tabs_content {}

以上数据都写在组件的wxml中,接下来来实现js动态数据

填入初始数据

Tabs.js

1
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
// components/Tabs/Tabs.js
Component({
/**
* 组件的属性列表
*/
properties: {
},

/**
* 组件的初始数据
*/
data: {
tabs: [
{
id: 0,
name: "首页",
isActive: true
},
{
id: 1,
name: "原创",
isActive: false
}
,
{
id: 2,
name: "分类",
isActive: false
}
,
{
id: 3,
name: "关于",
isActive: false
}
]
},

/**
* 组件的方法列表
*/
methods: {
}
})

Tab.wxml

1
2
3
4
5
6
7
8
9
10
11
12
13
<view class="tabs">

<view class="tabs_title">
<!-- 列表渲染 -->
<!-- class中三元表达式,根据item的isActive属性判断是否选中,选中则添加类名以显示样式 -->
<view wx:for="{{tabs}}" wx:key="id" class="title_item {{item.isActive?'active':''}}">
{{item.name}}
</view>
</view>

<view class="tabs_content"></view>

</view>

绑定点击事件

Tab.wxml

1
2
3
4
5
6
7
8
9
<view class="tabs_title">
<!-- 列表渲染 -->
<!-- class中三元表达式,根据item的isActive属性判断是否选中,选中则添加类名以显示样式 -->
<!-- data-index自定义属性,用于传递当前的索引值 -->
<view wx:for="{{tabs}}" wx:key="id" class="title_item {{item.isActive?'active':''}}" bindtap="handleItemTap"
data-index="{{index}}">
{{item.name}}
</view>
</view>

注意自定义组件的方法写在methods中

Tabs.js

1
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
methods: {
handleItemTap(e) {
// 查看索引所在的位置
console.log(e);

// 1.获取被点击的索引
// ES6常量const,只读不可改
// ES6解构赋值:const { index } = e.currentTarget.dataset;
const index = e.currentTarget.dataset.index;

// 2.获取原数组
// ES6变量let,块级作用域
// ES6解构赋值:let { tabs } = this.data;
let tabs = this.data.tabs;

// 3.循环数组:为当前索引项设置isActive:true,其余false
// ES6箭头函数
tabs.forEach((v, i) => {
i === index ? v.isActive = true : v.isActive = false
});

// 修改数据
this.setData({
tabs
})
}
}

以上数据都写在组件中,接下来来实现父向子传递数据

父向子传递数据

demo01.wxml

1
2
3
4
5
6
<!-- 
父组件demo01,子组件Tabs
父组件通过标签属性传递数据
子组件在properties中接收
-->
<Tabs abc="要传递的数据"></Tabs>

Tabs.js

1
2
3
4
5
6
7
8
9
properties: {
// 属性名
abc: {
// 接收的数据的类型
type: String,
// 默认值
value: ""
}
},

Tabs.wxml

1
2
<!-- 相当于data中的数据使,用{{}}渲染 -->
<view>{{abc}}</view>

接下来修改案例代码

  1. 将要传递的数据放在父组件的data中,即原先写在Tabs.js的data中的数据放在demo01.js的data中

    1
    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
    data: {
    tabs: [
    {
    id: 0,
    name: "首页",
    isActive: true
    },
    {
    id: 1,
    name: "原创",
    isActive: false
    }
    ,
    {
    id: 2,
    name: "分类",
    isActive: false
    }
    ,
    {
    id: 3,
    name: "关于",
    isActive: false
    }
    ]
    },
  2. 父组件通过标签属性传递数据

    demo01.wxml

    1
    <Tabs tabs="{{tabs}}"></Tabs>
  3. 子组件在properties中接收,最后效果与之前相同

    Tabs.js

    1
    2
    3
    4
    5
    6
    properties: {
    tabs: {
    type: Array,
    value: []
    }
    },

此时Tabs.js中代码仍然是在子组件当中修改tab数组,而不是在父组件的data中修改tab(可以在AppData窗口查看)

1
2
3
4
5
6
// this.data中找不到数据,则在properties中寻找
let tabs = this.data.tabs;
// 将tabs放入data当中
this.setData({
tabs
})

所以需要将处理数据放在父组件当中,而所需要的索引值则由子组件传递给父组件(子向父传递数据)

子向父传递数据

Tabs.js

1
2
3
4
5
6
7
8
methods: {
handleItemTap(e) {
// 1.获取被点击的索引
const index = e.currentTarget.dataset.index;
// 2.触发父组件中的自定义事件,并传递数据
this.triggerEvent("itemChange", { index }); //triggerEvent("自定义事件名", 要传递的数据)
}
}

demo01.wxml

1
2
3
4
5
6
<!-- 
子组件Tabs -> 父组件demo01
在子组件的标签中添加自定义事件
编写父组件js事件方法
-->
<Tabs tabs="{{tabs}}" binditemChange="handleItemChange"></Tabs>

demo01.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 自定义事件方法
handleItemChange(e) {
console.log(e);
// 接收传递的数据
const index = e.detail.index;
// 以下代码相同
let tabs = this.data.tabs;
tabs.forEach((v, i) => {
i === index ? v.isActive = true : v.isActive = false
});
this.setData({
tabs
})
},

AppData窗口查看即可

slot标签

slot占位符(插槽),父组件调用子组件传递一些标签来替换slot的位置

Tabs.wxml

1
2
3
<view class="tabs_content">
<slot></slot>
</view>

demo01.wxml

1
2
3
4
5
6
<Tabs tabs="{{tabs}}" binditemChange="handleItemChange">
<block wx:if="{{tabs[0].isActive}}">内容1</block>
<block wx:elif="{{tabs[1].isActive}}">内容2</block>
<block wx:elif="{{tabs[2].isActive}}">内容3</block>
<block wx:else>内容4</block>
</Tabs>

生命周期

应用

image-20210718141859157

1
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
// app.js
App({
// 应用 第一次启动 的时候触发,可用于最开始获取用户的个人信息等
onLaunch() {
console.log("onLaunch");
},

// 应用 显示 的时候触发,可用于对页面数据、页面效果进行重置
onShow() {
console.log("onShow");
// 可调用多次
},

// 应用 隐藏 的时候触发,可用于暂停或清除定时器
onHide() {
console.log("onHide");
},

// 应用 代码报错 的时候触发,可用于收集错误信息并发送到后台
onError(error) {
console.log("onError");
console.log(error);
},

// 应用 第一次启动找不到入口页面 的时候触发,可用于跳转
onPageNotFound() {
console.log("onPageNotFound");
wx.navigateTo({
url: '/pages/demo01/demo01',
})
}

})

页面

image-20210718141908133

1
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// pages/demo02/demo02.js
Page({

/**
* 页面的初始数据
*/
data: {

},

/**
* 生命周期函数--监听页面加载
* 发送异步请求初始化页面数据
*/
onLoad: function (options) {
console.log("onLoad");
},

/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
console.log("onShow");
},

/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
console.log("onReady");
},

/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
console.log("onHide");
},

/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
console.log("onUnload");
},

/**
* 页面相关事件处理函数--监听用户下拉动作
* 对页面初始化
*/
onPullDownRefresh: function () {
console.log("onPullDownRefresh");
},

/**
* 页面上拉触底事件的处理函数
* 触底加载更多数据
*/
onReachBottom: function () {
console.log("onReachBottom");
},

/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
console.log("onShareAppMessage");
},

/**
* 页面滚动
*/
onPageScroll() {
console.log("onPageScroll");
},

/**
* 页面尺寸改变
*/
onResize() {
console.log("onResize");
},

/**
* 当前是tab页,点击当前页的tab时触发
*/
onTabItemTap() {
console.log("onTabItemTap");
}
})

评论




🧡💛💚💙💜🖤🤍