跳至主要內容

组件

chanchaw大约 6 分钟mini

组件

概述

公共组件为项目全局中任意处页面组件都可以使用的组件,一般放置在项目根目录下的 components 下,一个组件一个目录,例如要创建自定义的 checkbox 组件,则创建目录为 components/custom-checkbox ,并在该目录下创建4个文件:custom-checkbox.jsoncustom-checkbox.wxsscustom-checkbox.jscustom-checkbox.wxml,注意第一个文件 custom-checkbox.json 中必须要有一个属性,否则小程序IDE报错

{
  "usingComponents": {}
}

自定义组件中不允许使用:标签选择器、ID选择器、属性选择器。推荐使用类选择器

组件复用机制 behaviors

小程序的 behaviors 类似 react 的 hook ,是一种代码复用的方式,可以将一些通用的逻辑和方法提取出来,然后在多个组件中复用,从而减少代码冗余,提高代码的可维护性。需要使用 Behaviors 方法,每个 behavior 可以包含一组属性、数据、生命周期函数和方法。

外部样式类

一般情况下页面和其中的组件的样式互不干扰,两者的样式是隔离的。不过在某些情况下页面想要修改其内部组件的样式的话就会很麻烦,在解除样式隔离后很可能导致样式冲突、样式调用时路径太深的情况,为解决这个问题小程序提示了 “外部样式类”。

// 自定义组件中通过属性 externalClasses 声明对外暴露的外部样式类的名称 extend-class
Component({
	externalClasses: ['extend-class'],
	properties: {},
	data: {},
	methods: {}
})

// 页面中传入外部样式类,key=自定义组件中声明的外部样式类的名称
// 后面的值是页面中自定义的类名称
<custom-cmpt extend-class="myclass">

组件生命周期

下面是组件自身的生命周期函数需要在 lifetimes 字段内进行声明,总共有5个:createted,attached,ready,moved,detached

Component({
	lifetimes: {
		created(){},
		attached(){},
		detached(){}
	}
})

下面是组件所在的页面的声明周期函数

Component({
	pageLifetimes:{
		show(){},// 组件所在页面展示(后台切换到前台)后触发
		hide(){} // 组件所在页面隐藏(前台切换后台、点击 tabBar)状态
	}
})

冷启动钩子顺序

路由跳转时的钩子顺序

热启动钩子顺序

样式隔离

自定义组件的样式隔离相关的属性如下面代码,

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

有三个选项:

  • isolated - 样式隔离,全局样式、页面样式都不会影响到自定义组件的样式。默认本选项

  • apply-shared - 页面样式可以影响到自定义组件的样式,但是自定义组件的样式不会向上影响到页面组件以及全局样式

  • shared - 在 apply-shared 的基础上,自定义组件的样式还可以影响到页面样式、全局样式,以及使用了 apply-shared 的自定义组件

custom-checkbox

使用技术点:动态样式、通过css更换元素位置、自定义组件 properties 页面组件通过 propertieschecked 设置默认勾选,为保证数据的单向流使用了 observers 监听传入属性 checked 赋值给内部数据 isChecked,之后都是通过修改内部数据 isChecked 影响数据和视图,保证数据流的单向操作

/***************** custom-checkbox.json *******************/
{
  "usingComponents": {}
}

/***************** custom-checkbox.ts *******************/
Component({
  options: {
    styleIsolation: 'shared'
  },
  properties: {
    label: {
      // 可用的数据类型有:String,Number,Boolean,Object,Array
      // 也可以设置 null,表示不限制类型
      type: String,
      value: '' // 默认空字符串
    },
    position: {
      type: String,
      value: 'right' // 文本默认显示在右边
    },
    checked: {// 默认不勾选
      type: Boolean,
      value: false
    }
  },
  observers:{
    checked: function(newVal){
      this.setData({
        isChecked: newVal
      })
    }
  },
  data:{
    isChecked: false
  },
  methods: {
    updateChecked(){
      this.setData({
        isChecked: !this.data.isChecked
      })
    },
    handleTap(){
      this.setData({
        isChecked: !this.data.isChecked
      })
    }
  }
})

/***************** custom-checkbox.wxml *******************/
<view class="custom-checkbox-container">
<view class="custom-checkbox-box {{ position === 'right' ? 'right' : 'left' }}">
  <!-- label在左边时文字右边会贴着 checkbox,不美观,所以当 label 在左边时给5px的间隙 -->
  <checkbox 
    class="{{ position === 'left' ? 'margin-left5' : '' }}" 
    checked="{{ isChecked }}" 
    bind:tap="updateChecked">
  </checkbox>
  <view class="label" bind:tap="handleTap">{{ label }}</view>
  <!-- 如果用户设置了属性 label 则不显示 slot 的元素,即 label 属性优先 -->
  <view wx:if="{{ label.length === 0 }}" bind:tap="handleTap"><slot /></view>
</view>
</view>

/***************** custom-checkbox.wxss 最后面3个样式代码是修改默认的复选框样式 *******************/
.custom-checkbox-container {
  display: inline-block;
}
.custom-checkbox-box {
  display: flex;
  align-items: center;
}

.custom-checkbox-box.left {
  flex-direction: row-reverse;
}
.custom-checkbox-box.right {
  flex-direction: row;
}
.margin-left5 {
  margin-left: 5px;
}

/* 修改复选框的默认样式,通过小程序官方的类名称进行修改 */
/* 复选框没有选中的样式 */
.custom-checkbox-box .wx-checkbox-input {
  width: 24rpx !important;
  height: 24rpx !important;
  border-radius: 50% !important;
  border: 1px solid #fda007 !important;
  margin-top: -6rpx;
}
/* 复选框选中的样式 */
.custom-checkbox-box .wx-checkbox-input-checked {
  background-color: #fda007 !important;
}
/* 复选框的 ✔ 样式 */
.custom-checkbox-box .wx-checkbox-input.wx-checkbox-input-checked:before {
  font-size: 22rpx;
  color: #fff
}

默认插槽

在自定义组件的 wxml 文件中使用元素 slot 即可使用默认插槽功能(此处之后会被更换为子节点 html 元素)

<view>
  <view>我是插槽自定义组件</view>
  <slot />
</view>

监听数据变动

自定义组件中通过属性 observers 监听 dataproperties 中数据的变化,下面代码中的回调函数接受到的参数是变动后的最新数据,回调函数的 key 是 data中的 key

Component({
  data: {
    num: 11
  },
  observers:{
    num: function(newNum){
      console.log(newNum)
    },
    'obj.**':function(newObj){
		// 监听本自定义组件的所有数据的变动
    }
  },
}

组件通信

父传子

页面组件使用自定义组件时候通过后者的 properties 中指定的属性,例如上面的案例自定义组件 custom-checkbox 中的 checked 。在自定义组件内部通过监听数据变动将父级组件传递来的数据复制给内部数据后再进行操作(保证数据的单向流动)

子传父

通过触发事件的方法实现。子组件中触发自定义事件,父组件中绑定该事件在父组件的函数中获取数据

<!-- 子组件发送自定义事件 -->
methods: {
    sendData(){
      this.triggerEvent('myevent', this.data.num)
    }
}
<!-- 父组件中绑定自定义事件 -->
<slot-cmpt bind:myevent="handleMyevent" />
<!-- 绑定方法中获取数据,传入参数的属性 event.detail 是子组件传递来的数据 -->
methods: {
    handleMyevent(event:any){
    	console.log(event)
    },
}

通过组件实例

为子组件指定ID,通过 selectComponent 方法获取组件后就可以得到子组件中的数据了(在 data 属性中)

<slot-cmpt id="childCmpt">
    
getData8Cmpt(){
  const cmpt = this.selectComponent("#childCmpt")
  console.log(cmpt)
  console.log(cmpt.data.num)
}