微信小程序-自定义组件

2020-09-26  本文已影响0人  逝去丶浅秋

一、自定义组件介绍

微信小程序提供了自定义组件扩展机制,允许我们使用自定义组件的方式来构建页面。

自定义组件可以使我们更好的复用一些功能。

二、创建自定义组件

在项目的pages文件夹下创建文件夹,例如customComponent文件夹,然后右键这个文件夹,选择新建Component,这时customComponent文件夹出现四个文件,和正常的创建的一样,下面介绍这四个文件和正常的不同之处:

#CusComponent.js:
Component({
  /**
   * 组件的属性列表
   */
  properties: {
  },
  /**
   * 组件的初始数据
   */
  data: {
  },
  /**
   * 组件的方法列表
   */
  methods: {
  }
})
#CusComponent.json
{
  "component": true,  //代表当前文件是一个组件
  "usingComponents": {} //使用组件写在括号里
}

js文件的头有Page变为Component,json文件里面多了"component": true,wxmlwxss文件和原来的一样。

三、如何使用自定义组件

想在主页index页面使用组件,那么打开存放页面的pages文件夹下的index文件夹中的index.json,在usingComponents中添加如下代码:

{
  "usingComponents": {
    "CusComponent":"/pages/customComponent/cusComponent"
  }
}

usingComponents里面是键值对,左边是要使用组件的名字,右边是其路径。

接着在index.wxml中使用<CusComponent></CusComponent>引入组件。

四、自定义组件中.js文件的属性介绍

#js文件中的data属性:
data: {
    itemList:[
      {id:0,name:"首页"},
      {id:1,name:"类别"},
      {id:2,name:"关于"},
    ]
  }

此时在wxml文件中可以像下面这样写:

<view wx:for="{{itemList}}" wx:key="key">{{item.name}}</view>

结果:首页  类别  关于

因为wx:for中列表遍历默认的是item,所以可以直接用item.name来获取name

<view bindTap="handleMethod"></view>

methods: {
  handleMethod(e){
    //语句let itemList = this.data.itemList;和下面的相等,解构
    let {itemList} = this.data;
    //[].forEach遍历数组,遍历的时候修改了v,也会导致源数组被修改
    //使用这种写法则相当于重新拷贝了一份数据let items = JSON.parse(JSON.stringify(this.data.itemList));
    itemList.forEach((v,i) => i===index?v.isActive=true:v.isActive=false)
  }
}

multipleSlots:true,在组件定义时的选项中启动多slot支持
styleIsolation:isolated,启动样式隔离,具体配置选项参见:(八)自定义组件的样式
addGlobalClass:true,表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面。这个选项等价于设置 styleIsolation: apply-shared
virtualHost:true,将自定义节点设置成虚拟的,我们不希望自定义组件的这个节点本身可以设置样式、响应 flex 布局等,而是希望自定义组件内部的第一层节点能够响应 flex 布局或者样式由自定义组件本身完全决定。

/* 组件 custom-component.js */
Component({
  options: {
    addGlobalClass: true,
  }
})
属性 类型 是否必填 描述
properties Object|Map 组件的对外属性,是属性名到属性设置的映射表
data Object 组件的内部数据,和properties用用于组件的模版渲染
observers Object 组件数据字段监听器,用于监听properties和data的变化
methods Object 组件的方法,包括事件响应函数和任意的自定义方法
created Function 组件生命周期函数,在组件实例刚刚被创建时执行,注意此时不能调用setData
attached Function 组件生命周期函数,在组件实例进入页面节点树时执行
ready Function 组件生命周期函数,在组件布局完成后执行
moved Function 组件生命周期函数,在组件实例被移动到节点树另一个位置时执行
detached Function 组件生命周期函数,在组件实例被从页面节点树移除时执行

五、父组件向子组件传值

直接看代码:

#父组件的wxml文件,在此文件中引入CusComponent组件
//parentData为要传递的数据名称,parent_data为数据内容
<CusComponent parentData="parent_data"></CusComponent>
#自定义组件的.js文件里的properties属性
properties: {
    //要接收的数据名称
    parentData:{
      //要接收的数据类型
      type:String,
      //要接收的数据
      value:''
    }
  }
<!-- 自定义组件的wxml文件 -->
<view wx:for="{{itemList}}" wx:key="key">{{item.name}}</view>
<!-- parentData就是要接收数据的名称 -->
<view class="content">{{parentData}}</view>

过程:
1、父组件通过parentData="parent_data"将数据传到子组件
2、子组件的properties接收到数据后,根据父组件数据名parentData,存到parentDatavalue
3、子组件的wxml文件直接使用{{parentData}}来拿到父组件传递过来的数据。

六、子组件向父组件传值

子组件给父组件传递数据通过自定义组件触发事件来进行传递。先看代码:

#子组件的.js文件
methods: {
  handleActive(e){
    const {index} = e.currentTarget.dataset;
    //triggerEvent("自定义事件名称",要传递的数据),触发事件
    this.triggerEvent("itemChange",{index});
  }
}
#父组件的wxml文件
<!--
当子组件事件触发后,bindbinditemChange会执行其后的方法changeItemList()
binditemChange="changeItemList";
1、binditemChange:其格式是bind+事件名称,事件的名称是子组件中this.triggerEvent("itemChange",{index});的事件名称
2、changeItemList():是父组件.js文件中的方法
-->
< CusComponent itemList="{{itemList}}" binditemChange="changeItemList"></CusComponent>
#父组件.js文件中的方法
changeItemList(e){
  const index = e.detail.index;
  let itemList = this.data.itemList;
  itemList.forEach((v,i) => {
    i===index?v.isActive=true:v.isActive=false
  });
  this.setData({
    itemList:itemList
  })
}

过程:
1、点击子组件后调用子组件的handleActive(e),此方法中有个自定义组件触发事件this.triggerEvent("itemChange",{index});
2、触发父组件wxml文件引用的<CusComponent/>组件中的binditemChange指向的changeItemList()方法
3、在父组件的.js文件中的changeItemList()方法中对子组件传递过来的数据进行处理

triggerEvent方法三个参数解释:
'myevent':自定义事件的名称
myEventDetail:detail对象,提供给事件监听函数,如上面传递的数据
myEventOption:触发事件的选项,不是必填项。

myEventOption的三个选项解释:
bubbles:事件是否冒泡。默认值false
composed:事件是否可以穿越组件边界,为false时,事件将只能在引用组件的节点树上触发,不进入其他任何组件内部。默认值false
capturePhase:事件是否拥有捕获阶段。默认值false

七、自定义组件中的 slot 标签

组件的写法和页面相同。组件与组件数据结合后生产的节点树,将被插入到组件的引用位置上。

在组件中提供了一个<slot>节点,用于承载组件引用时提供的子节点。

注意:在模板中引用到的自定义组件及其对应的节点名需要在 json 文件中显式定义,否则会被当作一个无意义的节点。除此以外,节点名也可以被声明为抽象节点。

#父组件wxml中引用的子组件
<cusComponent>
  <view>父组件传递过来的节点,相当于子组件中的slot</view>
</cusComponent>
#子组件wxml中
<view class="content">
  <slot></slot>
</view>

上面的代码就会让父组件传递过来的节点,相当于子组件中的slot在你的自定义组件中显示。

需要多个slot时,如何在组件js中声明:

#子组件的.js文件
Component({
  options: {
    multipleSlots: true // 在组件定义时的选项中启用多slot支持
  },
})

此时就可以在组件的wxml中使用多个slot,以不用的name来区分:

#子组件的.wxml文件
<view class="content">
  <slot name="name1"></slot>
  <slot name="name2"></slot>
</view>

八、自定义组件的样式

1、组件样式

组件对应 wxss 文件的样式,只对组件wxml内的节点生效。编写组件样式时,需要注意以下几点:

#a { } /* 在组件中不能使用 */
[a] { } /* 在组件中不能使用 */
button { } /* 在组件中不能使用 */
.a > .b { } /* 除非 .a 是 view 组件节点,否则不一定会生效 */

除此以外,组件可以指定它所在节点的默认样式,使用 :host 选择器(需要包含基础库 [1.7.2]。

/* 组件 custom-component.wxss */
:host {
  color: yellow;
}
2、组件样式隔离

默认情况下,自定义组件的样式只受到自定义组件 wxss 的影响。除非以下两种情况:

Component({
  options: {
    styleIsolation: 'isolated'
  }
})

styleIsolation的选项:
isolated 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(一般情况下的默认值);
apply-shared 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面;
shared 表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。(这个选项在插件中不可用。)

使用后两者时,请务必注意组件间样式的相互影响。

如果这个Component 构造器用于构造页面,则默认值为 shared ,且还有以下几个额外的样式隔离选项可用:

在 Component 的 options中设置addGlobalClass: true 。 这个选项等价于设置 styleIsolation: apply-shared,但设置了 styleIsolation 选项后这个选项会失效。

/* 组件 custom-component.js */
Component({
  options: {
    addGlobalClass: true,
  }
})
3、外部样式类、引用页面或父组件的样式、虚拟化组件节点

参见官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html

写在最后:

如果文章中有错误或是表达不准确的地方,欢迎大家评论中指正,以便我完善。
文章我也会根据所学到新的知识不断更新。

上一篇 下一篇

猜你喜欢

热点阅读