微信小程序-自定义组件

一、自定义组件介绍

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

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

二、创建自定义组件

在项目的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中使用引入组件。

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

  • data属性:组件的初始数据
    例如添加如下数据:
#js文件中的data属性:
data: {
    itemList:[
      {id:0,name:"首页"},
      {id:1,name:"类别"},
      {id:2,name:"关于"},
    ]
  }

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

{{item.name}}

结果:首页  类别  关于

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

  • methods属性:组件的方法列表
    在正常页面中方法是存放在.js文件data属性的同层级下的。而在自定义组件中必须放在.js文件methods里面,放在外面方法无效。


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)
  }
}
  • properties属性:组件的对外属性,是属性名到属性设置的映射表。里面存放的是父组件传递过来的数据
    参见:五、父组件向子组件传值
  • options属性:配置一些功能的选项
    可配置的选项:

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为数据内容

#自定义组件的.js文件里的properties属性
properties: {
    //要接收的数据名称
    parentData:{
      //要接收的数据类型
      type:String,
      //要接收的数据
      value:''
    }
  }

{{item.name}}

{{parentData}}

过程:
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文件

< CusComponent itemList="{{itemList}}" binditemChange="changeItemList">
#父组件.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文件引用的组件中的binditemChange指向的changeItemList()方法
3、在父组件的.js文件中的changeItemList()方法中对子组件传递过来的数据进行处理

  • triggerEvent方法参数:triggerEvent('myevent',{myEventDetail},{myEventOption});

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

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

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

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

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

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

#父组件wxml中引用的子组件

  父组件传递过来的节点,相当于子组件中的slot

#子组件wxml中

  

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

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

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

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

#子组件的.wxml文件

  
  

八、自定义组件的样式

1、组件样式

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

  • 请使用class选择器:组件和引用组件的页面不能使用id选择器(#a)、属性选择器([a])和标签名选择器,请改用class选择器。
  • 避免使用后代选择器:组件和引用组件的页面中使用后代选择器(.a .b)在一些极端情况下会有非预期的表现,如遇,请避免使用。
  • 子元素选择器只能用于view及子节点:子元素选择器(.a>.b)只能用于 view 组件与其子节点之间,用于其他组件可能导致非预期的情况。
  • 继承样式:继承样式,如 font 、 color ,会从组件外继承到组件内。
  • app.wxss样式组件对自定义组件无效:除继承样式外, app.wxss 中的样式、组件所在页面的的样式对自定义组件无效(除非更改组件样式隔离选项)。
#a { } /* 在组件中不能使用 */
[a] { } /* 在组件中不能使用 */
button { } /* 在组件中不能使用 */
.a > .b { } /* 除非 .a 是 view 组件节点,否则不一定会生效 */

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

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

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

  • app.wxss 或页面的 wxss 中使用了标签名选择器(或一些其他特殊选择器)来直接指定样式,这些选择器会影响到页面和全部组件。通常情况下这是不推荐的做法。
  • 指定特殊的样式隔离选项 styleIsolation 。
Component({
  options: {
    styleIsolation: 'isolated'
  }
})

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

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

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

  • page-isolated 表示在这个页面禁用 app.wxss ,同时,页面的 wxss 不会影响到其他自定义组件;
  • page-apply-shared 表示在这个页面禁用 app.wxss ,同时,页面 wxss 样式不会影响到其他自定义组件,但设为 shared 的自定义组件会影响到页面;
  • page-shared 表示在这个页面禁用 app.wxss ,同时,页面 wxss 样式会影响到其他设为 apply-sharedshared 的自定义组件,也会受到设为 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

写在最后:

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

你可能感兴趣的:(微信小程序-自定义组件)