# 9.自定义组件

类似vue或者react中的自定义组件

⼩程序允许我们使⽤⾃定义组件的⽅式来构建⻚⾯。

# 1.创建⾃定义组件

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

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

xcooo

在⽂件夹内 components/myHeader ,创建组件名为 myHeader

xcooo

# 1.1.声明组件

⾸先需要在组件的 json ⽂件中进⾏⾃定义组件声明 myHeader.json

{  
  "component": true 
}
1
2
3

# 1.2.编辑组件

同时,还要在组件的 wxml ⽂件中编写组件模板,在 wxss ⽂件中加⼊组件样式 slot 表⽰插槽,类似vue中的slot myHeader.wxml

<!-- 这是自定义组件的内部WXML结构 --> 
<view class="inner">  
   	{{innerText}}    
	<slot></slot> 
</view>
1
2
3
4
5

在组件的 wxss ⽂件中编写样式

注意:在组件wxss中不应使用ID选择器、属性选择器和标签名选择器。

myHeader.wxss

/* 这里的样式只应用于这个自定义组件 */ 
.inner {  
  color
}
1
2
3
4

# 1.3.注册组件

在组件的 js ⽂件中,需要使⽤ Component() 来注册组件,并提供组件的属性定义、内部数据和 ⾃定义⽅法 myHeader.js

Component({  
  properties: {    
    // 这里定义了innerText属性,属性值可以在组件使用时指定    
    innerText: {      
      // 期望要的数据是 string类型      
      type: String,   
      value: 'default value',    
    }  
  },  
  data: {    
    // 这里是一些组件内部数据    
    someData: {}  
  },  
  methods: {    
    // 这里是一个自定义方法    
    customMethod: function(){}  
  } 
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 2.声明引⼊⾃定义组件

⾸先要在⻚⾯的 json ⽂件中进⾏引⽤声明。还要提供对应的组件名和组件路径

index.wxxml

{   
  // 引用声明  
  "usingComponents": {    
    // 要使用的组件的名称     // 组件的路径    
    "my-header":"/components/myHeader/myHeader"  
  } 
}
1
2
3
4
5
6
7

# 3.⻚⾯中使⽤⾃定义组件

<view>  
  <!-- 以下是对一个自定义组件的引用 -->  
  <my-header inner-text="Some text">    
    <view>用来替代slot的</view>    
  </my-header> 
</view>
1
2
3
4
5
6

# 4.其他属性

# 5.定义段与⽰例⽅法

Component 构造器可⽤于定义组件,调⽤ Component 构造器时可以指定组件的属性、数据、⽅法 等。

定义段 类型 是否必填 描述
properties Object Map 组件的对外属性,是属性名到属性设置的映射表,参⻅下⽂
data Object 组件的内部数据,和 properties properties ⼀同⽤于组件的模板渲 染
observers Object 组件数据字段监听器,⽤于监听properties和data的变 化,参⻅数据监听器 (opens new window)
methods Object 组件的⽅法,包括事件响应函数和任意的⾃定义⽅法,关于 事件响应函数的使⽤,参⻅ 组件事件 (opens new window)
created Function 组件⽣命周期函数,在组件实例刚刚被创建时执⾏,注意此 时不能调⽤ setData ,参⻅组件⽣命周期 (opens new window)
attached Function 组件⽣命周期函数,在组件实例进⼊⻚⾯节点树时执⾏,参 ⻅组件⽣命周期 (opens new window)
ready Function 组件生命周期函数. 在组件布局完成后执行, 参见 组件生命周期 (opens new window)
moved Function 组件⽣命周期函数,在组件实例被移动到节点树另⼀个位置 时执⾏,参⻅组件⽣命周期 (opens new window)
detached Function 组件⽣命周期函数,在组件实例被从⻚⾯节点树移除时执⾏,参⻅组件⽣命周期 (opens new window)

# 6.组件-⾃定义组件传参

tab栏案例

1.⽗组件通过属性的⽅式给⼦组件传递参数

xcooo
<!-- 
  1.父组件(页面) 向子组件 传递数据 通过 标签属性的方式来传递
    1.在子组件上进行接收 properties
    2.子组件把这个数据当成是data中的数据直接用即可
  2.子向父传递数据 通过事件的方式传递
    1.在子组件的标签上加入一个 自定义事件
 -->
<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>

// js 
Page({

  /**
   * 页面的初始数据
   */
  data: {
    tabs: [
      {
        id:0,
        name: '首页',
        isActive: true
      },
      {
        id:1,
        name: '原创',
        isActive: false
      },
      {
        id:2,
        name: '分类',
        isActive: false
      },
      {
        id:0,
        name: '关于',
        isActive: false
      }
    ]
  },
  handleItemChange(e){
    // 接收传递过来的参数
    const {index} = e.detail
    const {tabs} = this.data
    tabs.forEach((v,i)=>{i===index?v.isActive=true:v.isActive=false})
    this.setData({
        tabs
      })
  },

})
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

2.⼦组件通过事件的⽅式向⽗组件传递参数

// 触发父组件的自定义事件  同时传递数据给 父组件
 this.triggerEvent('父组件自定义事件的名称', 要传递的参数)
1
2
// 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
    wx:for="{{tabs}}"
    wx:key="id"
    class="title_item {{item.isActive?'active':''}}"
    bindtap="handleTap"
    data-index="{{index}}"
    >
      {{item.name}}
    </view>
      
  </view>
  <view class="tabs_content">
    <!-- 
      slot标签是一个占位符 插槽 
      等到 父组件调用 子组件的时候 再传递 标签过来 最终 这些被传递的标签  就会替换 slot 插槽的位置
    -->
    <slot></slot>
  </view>
</view>
 
// js
Component({
  /**
   * 里面存放的是 要从父组件中接收的数据
   */
  properties: {
    // 要接收的数据的名称
    // aaa: {
    //   // type 要接收的数据的类型
    //   type:String,
    //   // value 默认值
    //   value:""
    // }
    tabs: {
      type:Array,
      value:[]
    }
  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   1.页面.js 文件中 存放事件回调函数的时候 存放再data同层级下!!!
   2.组件.js 文件中 存放事件回调函数的时候 必须要存放再 methods 中!!!
   */
  methods: {
    handleTap(e){
      // 1.绑定点击事件 需要再methods中绑定
      // 2.获取被点击的索引
      // 3.获取原数组
      // 4.对数组循环
        //1.对每一个循环项 选中属性 改为false
        //2.给当前的索引的 项 添加激活选中效果就可以了
      
      // 5.点击事件触发的时候
          // 触发父组件的自定义事件  同时传递数据给 父组件
          // this.triggerEvent('父组件自定义事件的名称', 要传递的参数)
      
      // 1.获取索引
      const {index} = e.currentTarget.dataset
      // 触发父组件的自定义事件  同时传递数据给 父组件
      this.triggerEvent('itemChange', {index})

      // 2.获取data中的数组
      // 解构 对 复杂数据进行结构的时候, 复制了一份 变量的引用而已
      // 最严谨的做法 重新拷贝一份 数组, 再对数组的备份进行处理
      // let tabs = JSON.parse(JSON.stringify(this.data.tabs))
      // 不要直接修改 this.data.数据
      // const {tabs} = this.data
      // 3.循环数组
      // tabs.forEach((v,i)=>{i===index?v.isActive=true:v.isActive=false})
      // 4.重新赋值
      // this.setData({
      //   tabs
      // })
    }
  }
})

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
91

# 6.1.过程

1.⽗组件把数据 传递到⼦组件的 tabItems 属性中

2.⽗组件监听 onMyTab 事件

3.⼦组件触发 bindmytap 中的 mytap 事件

​ 1.⾃定义组件触发事件时,需要使⽤ triggerEvent ⽅法,指定 事件名 、 detail 对象

4.⽗->⼦动态传值 this.selectComponent("#tabs") ; ⽗组件代码

// page.wxml 
 
<tabs tabItems="{{tabs}}" bindmytap="onMyTab" >  
  内容-这里可以放插槽 
</tabs>
 
// page.js  
data: {    
  tabs:[      
    {name:"体验问题"},      
    {name:"商品、商家投诉"}    
  ]
},  
onMyTab(e){    
   console.log(e.detail);   // 此时父组件接收子组件过来数据需要通过 e.detail 获取
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

子组件代码

// com.wxml 
<view class="tabs">  
  <view class="tab_title"  >    
    // 使用 父组件 传递过来的数据
    <block  wx:for="{{tabItems}}" wx:key="{{item}}">      
      <view bindtap="handleItemActive" data-index="{{index}}">{{item.name}}</view>    
        </block>  
  </view>  
  <view class="tab_content">    
      <slot></slot>  
  </view> 
</view>
 
  
// com.js 
  Component({  
    // 接收父组件传递过来的数据
    properties: {    
      tabItems:{      
        type:Array,      
        value:[]    
      }  
    }, 
    /**   * 组件的初始数据   */  
    data: {  
      
    },
  /**   * 组件的方法列表   */ 
    methods: {    
      handleItemActive(e){      
         // 触发父组件的自定义事件  同时传递数据给 父组件
        this.triggerEvent('mytap','haha');    
      }  
    } 
  })
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

# 7.⼩结

  • 1.标签名是中划线的⽅式

  • 2.属性的⽅式也是要中划线的⽅式

  • 3.其他情况可以使⽤驼峰命名

​ - 1.组件的⽂件名如 myHeader.js 的等

​ - 2.组件内的要接收的属性名如 innerText

上次更新: 2020/10/27 下午11:58:10