小程序自定义组件

news2024/11/15 17:53:04

自定义组件

1. 创建-注册-使用组件

组件介绍

小程序目前已经支持组件化开发,可以将页面中的功能模块抽取成自定义组件,以便在不同的页面中重复使用;

也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护。

开发中常见的组件有两种:

  1. 公共组件:将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用
  2. 页面组件:将复杂的页面拆分成多个低耦合的模块,有助于代码维护

如果是公共组件,建议将其放在小程序的目录下的 components 文件夹中

如果是页面组件,建议将其放在小程序对应页面目录下,当然你也可以放到页面的 components 文件夹中

同时建议:一个组件一个文件夹,文件夹名称和组件名称保持一致

📌 注意事项

  1. 自定义组件的需要在 json 文件中需要配置 component 字段设为 true
  2. 自定义组件通过 Component 构造器进行构建,在构造器中可以指定组件的属性、数据、方法等

创建自定义组件:

创建组件的步骤很简单,以公共组件为例,创建的步骤如下:

  1. 在小程序的目录下新建 components 文件夹

  2. components 文件夹上,点击右键,选择新建文件夹 ,然后输入文件夹名称,我们建议文件夹的名称和组件的名称保持一致,这样方便后期对组件进行维护。我们这里新的的组件名称叫做:custom-checkbox

  3. 在新建的组件文件夹上,点击右键,选择新建 Component,然后输入组件的名称,组件的名称建议和文件夹保持一致

  4. 此时就已经创建了一个功能组件
    在这里插入图片描述

使用自定义组件

开发中常见的组件主要分为 公共组件 和 页面组件 两种,因此注册组件的方式也分为两种:

  1. 全局注册:在 app.json 文件中配置 usingComponents 节点进行引用声明,注册后可在任意组件使用
  2. 局部注册:在页面的 json 文件中配置 usingComponents 节点进行引用声明,只可在当前页面使用

在这里插入图片描述

在配置 usingComponents 节点进行引用声明时,需要提供自定义组件的标签名和对应的自定义组件文件路径,语法如下:

{
  "usingComponents": {
    "自定义组件的标签名": "自定义组件文件路径"
  }
}

这样,在页面的 wxml 中就可以像使用基础组件一样使用自定义组件。节点名即自定义组件的标签名,节点属性即传递给组件的属性值。

{
  "usingComponents": {
    "custom-checkbox": "/components/custom-checkbox/custom-checkbox"
  }
}
<!--pages/index/index.wxml-->

<view>
  <!-- 将导入的自定义组件当成标签使用 -->
  <custom-checkbox
                   />
</view>

2. 自定义组件-数据和方法

在组件的 .js 中,需要调用 Component 方法创建自定义组件,Component 中有以下两个属性:

data 数据:组件的内部数据

methods 方法:在组件中事件处理程序需要写到 methods 中才可以

落地代码:

➡️ components/custom-checkbox/custom-checkbox.wxml

<!--components/custom-checkbox/custom-checkbox.wxml-->
<!-- <text>我是自定义组件</text> -->

<view class="custom-checkbox-container">
  <view class="custom-checkbox-box">
    <checkbox checked="{{ isChecked }}" bindtap="updateChecked" />
  </view>
</view>

➡️ components/custom-checkbox/custom-checkbox.wxss

/* components/custom-checkbox/custom-checkbox.wxss */

.custom-checkbox-container {
  display: inline-block;
}

➡️ components/custom-checkbox/custom-checkbox.js

Component({

  /**
   * 组件的初始数据:用来定义当前组件内部所需要使用的数据
   */
  data: {
    isChecked: false
  },

  /**
   * 组件的方法列表:在组件中,所有的事件处理程序都需要写到 methods 方法中
   */
  methods: {
    
    // 更新复选框的状态
    updateChecked () {

      this.setData({
        isChecked: !this.data.isChecked
      })

      console.log(this.data.isChecked)
    }

  }
  
})

➡️ app.json

{
  "usingComponents": {
    "custom-checkbox": "./components/custom-checkbox/custom-checkbox"
  }
}

➡️ index.wxml

<custom-checkbox />

<view class="line"></view>

<custom-checkbox />

3. 自定义组件-属性

属性 Properties 是指组件的对外属性,主要用来接收组件使用者传递给组件内部的数据,和 data 一同用于组件的模板渲染

📌 注意事项:

  1. 设置属性类型需要使用 type 属性,属性类型是必填项,value 属性为默认值
  2. 属性类型可以为 String、Number、Boolean、Object、Array ,也可以为 null 表示不限制类型

落地代码:

➡️ index.wxml

<!-- label 文本显示的内容 -->
<!-- position 控制文本显示的位置 -->

<custom-checkbox label="我已阅读并同意 用户协议 和 隐私协议" position="right" />

<view class="line"></view>

<custom-checkbox label="匿名提交" position="left" />

➡️ components/custom-checkbox/custom-checkbox.wxml

<!--components/custom-checkbox/custom-checkbox.wxml-->
<!-- <text>我是自定义组件</text> -->

<view class="custom-checkbox-container">
+   <view class="custom-checkbox-box {{ position === 'right' ? 'right' : 'left' }}">
+     <checkbox class="custom-checkbox" checked="{{ isChecked }}" bindtap="updateChecked" />
+ 
+     <view>
+       <text>{{ label }}</text>
+     </view>
  </view>
</view>

➡️ components/custom-checkbox/custom-checkbox.wxss

/* components/custom-checkbox/custom-checkbox.wxss */

.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;
}

.custom-checkbox {
  margin-left: 10rpx;
}

➡️ components/custom-checkbox/custom-checkbox.js

Component({

+   /**
+    * 组件的属性列表:组件的对外属性,主要用来接收组件使用者传递给组件内部的属性以及数据
+    */
+   properties: {
+     // 如果需要接收传递的属性,有两种方式:全写、简写
+     // label: String
+ 
+     label: {
+       // type 组件使用者传递的数据类型
+       // 数据类型:String、Number、Boolean、Object、Array
+       // 也可以设置为 null,表示不限制类型
+       type: String,
+       value: ''
+     },
+ 
+     // 文字显示位置
+     position: {
+       type: String,
+       value: 'right'
+     }
+   },

  /**
   * 组件的初始数据:用来定义当前组件内部所需要使用的数据
   */
  data: {
    isChecked: false
  },

  /**
   * 组件的方法列表:在组件中,所有的事件处理程序都需要写到 methods 方法中
   */
  methods: {
    
    // 更新复选框的状态
    updateChecked () {

      this.setData({
        isChecked: !this.data.isChecked,
+        // label: '在组件内部也可以修改 properties 中的数据'
      })

+       // 在 JS 中可以访问和获取 properties 中的数据
+       // 但是一般情况下,不建议修改,因为会造成数据流的混乱
+       // console.log(this.properties.label)
      // console.log(this.data.isChecked)
    }

  }
  
})

4. 组件 wxml 的 slot

在使用基础组件时,可以给组件传递子节点传递内容,从而将内容展示到页面中,自定义组件也可以接收子节点内容

只不过在组件模板中需要定义 <slot /> 节点,用于承载组件引用时提供的子节点
在这里插入图片描述

默认情况下,一个组件的 wxml 中只能有一个 slot 。需要使用多 slot 时,可以在组件 js 中声明启用。

同时需要给 slot 添加 name 来区分不同的 slot,给子节点内容添加 slot 属性来将节点插入到 对应的 slot 中
在这里插入图片描述

知识点讲解:

➡️ custom01.html

<view>
  <slot name="slot-top" />
  <!-- slot 就是用来接收、承载子节点内容 -->
  <!-- slot 只是一个占位符,子节点内容会将 slot 进行替换 -->
  <!-- 默认插槽 -->
  <view><slot /></view>

  <slot name="slot-bottom" />
</view>

➡️ custom01.js

// components/custom01/custom01.js

Component({

  options: {
    // 启用多 slot 支持
    multipleSlots: true
  }

})

➡️ cart.wxml

<custom01>
  <text slot="slot-top">我需要显示到顶部</text>
    
  <!-- 默认情况下,自定义组件的子节点内容不会进行展示 -->
  <!-- 如果想内容进行展示,需要再组件模板中定义 slot 节点 -->
  我是子节点内容
    
  <text slot="slot-bottom">我需要显示到低部</text>
</custom01>

完善复选框案例

➡️ custom-checkbox.html

<!--components/custom-checkbox/custom-checkbox.wxml-->
<!-- <text>我是自定义组件</text> -->

<view class="custom-checkbox-container">
  <view class="custom-checkbox-box {{ position === 'right' ? 'right' : 'left' }}">
    <checkbox class="custom-checkbox" checked="{{ isChecked }}" bindtap="updateChecked" />

+     <view>
+       <!-- lable 和 子节点内容都进行了展示 -->
+       <!-- 要么展示 lable 要么展示 子节点内容 -->
+       <!-- 如果用户传递了 lable 属性,就展示 lable -->
+       <!-- 如果用户没有传递 lable 属性,就展示 子节点内容 -->
+       <text wx:if="{{ label !== '' }}">{{ label }}</text>
+ 
+       <slot wx:else />
+     </view>
  </view>
</view>

➡️ index.html

<!-- label 文本显示的内容 -->
<!-- position 控制文本显示的位置 -->
<custom-checkbox label="我已阅读并同意 用户协议 和 隐私协议" position="right">
  我已阅读并同意 用户协议 和 隐私协议 - 111
</custom-checkbox>

<view class="line"></view>

<custom-checkbox label="匿名提交" position="left">
  匿名提交 - 222
</custom-checkbox>

5. 组件样式以及注意事项

选择器使用注意事项:

类似于页面,自定义组件拥有自己的 wxss 样式,组件对应 wxss 文件的样式,只对组件wxml内的节点生效。

编写组件样式时,需要注意以下几点:

  1. app.wxss 或页面的 wxss 中使用了标签名(view)选择器(或一些其他特殊选择器)来直接指定样式
    这些选择器会影响到页面和全部组件,通常情况下这是不推荐的做法

  2. 组件和引用组件的页面不能使用 id 选择器(#a)、属性选择器([a]) 和 标签名选择器,请改用 class 选择器

  3. 组件和引用组件的页面中使用后代选择器(.a .b)在一些极端情况下会有非预期的表现,如遇,请避免使用

  4. 子元素选择器(.a>.b)只能用于 view 组件与其子节点之间,用于其他组件可能导致非预期的情况。

  5. 继承样式,如 font 、 color ,会从组件外继承到组件内。

  6. 除继承样式外, 全局中的样式、组件所在页面的的样式对自定义组件无效 (除非更改组件样式隔离选项)

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

落地代码:

➡️ custom02.wxml

<text id="content" class="content son">
  <text class="label">给自定义组件设置样式</text>
</text>

➡️ custom02.wxss

/* components/custom02/custom02.wxss */

/* 第一个注意事项:在自定义的 wxss 文件中,不允许使用标签选择器,ID 选择器,属性选择器 */
/* 请改为 class 选择器 */
/* text {
  color: lightseagreen;
} */

/* #content {
  color: lightseagreen;
} */

/* [id=content] {
  color: lightseagreen;
} */

/* .content {
  color: lightseagreen;
} */

/* 第二个注意事项:子选择器,只能用于 view 和 子组件,用于其他组件可能会出现样式失效的问题 */
/* .content > .label {
  color: lightseagreen;
} */

/* 第三个注意事项:继承样式,例如:color\font 都会从组件外继承 */

/* 第四个注意事项:全局样式、组件所在页面的样式文件中的样式都对自定义组件无效 */

/* 第五个注意事项:官方不推荐做法 */
/* 不建议在 全局样式文件 以及 父级页面之间使用标签选择器设置样式 */
/* 如果是在全局样式文件中设置样式,会影响项目中全部的相同组件 */
/* 如果是再页面样式文件中设置样式,会影响当前页面所有的相同组件 */

/* 第六个注意事项: */
/* 组件和组件使用者,如果使用了后代选择器,可能会出现一些非预期情况 */
/* 如果出现,请避免 */

➡️ cate.wxml

<view class="custom parent">
  <view>
    <custom02 />

    <view class="son test">我是父级页面中的结构</view>
  </view>
</view>

➡️ cate.wxss

/* pages/cate/cate.wxss */

/* .custom  {
  color: lightseagreen;
  font-size: 50rpx;
} */

/* .label {
  color: lightseagreen;
} */

/* text {
  color: lightseagreen;
} */

.parent .son.test {
  color: lightsalmon;
}

➡️ app.wxss

/* .label {
  color: lightseagreen;
} */

/* text {
  color: lightseagreen;
} */

6. 组件样式隔离

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

  1. app.wxss 或页面的 wxss 中使用了标签名(view)选择器(或一些其他特殊选择器)来直接指定样式,这些选择器会影响到页面和全部组件。通常情况下这是不推荐的做法。

  2. 指定特殊的样式隔离选项 styleIsolation

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

styleIsolation 选项它支持以下取值:

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

落地代码:

➡️ custom03.wxml

<!--components/custom03/custom03.wxml-->

<text class="label">演示组件样式隔离</text>

➡️ custom03.wxss

/* components/custom03/custom03.wxss */

.test {
  color: lightseagreen;
  font-size: 50rpx;
}

➡️ custom03.js

// components/custom03/custom03.js
Component({

  options: {

    // styleIsolation:配置组件样式隔离

    // isolated:开启样式隔离,默认值
    // 在默认情况下,自定义组件和组件使用者如果存在相同的类名,类名不会相互影响

    // apply-shared:表示组件使用者、页面的 wxss 样式能够影响到自定义组件
    // 但是自定义组件的样式不会影响组件使用者、页面的 wxss 样式
    // styleIsolation: "apply-shared"

    // shared:表示组件使用者、页面的 wxss 样式能够影响到自定义组件
    // 自定义组件的样式会影响组件使用者、页面的 wxss 样式
    // 和其他使用了 apply-share 以及 share 属性的自定义组件
    styleIsolation: 'shared'

  }
    
})

➡️ cate.wxml

<custom03 />

➡️ cate.wxss

.label {
  color: lightsalmon;
}

7. 拓展-小程序修改checkbox样式

知识点:

技巧:在官方文档,找到官方提供的案例,审查元素,就能看到对应的类名

在这里插入图片描述

📌 注意事项

  1. .custom-checkbox .wx-checkbox-input {}:复选框没有选中时默认的样式
  2. .custom-checkbox .wx-checkbox-input-checked {}: 复选框选中时默认的样式
  3. .custom-checkbox .wx-checkbox-input.wx-checkbox-input-checked:before {}:复选框选中时 √ 样式

这几个类名,在全局样式文件、页面样式文件都可以对修改复选框样式,

但是在自定义组件内部使用的时候,需要添加 styleIsolation: 'shared' 属性

落地代码:

➡️ components/custom-checkbox/custom-checkbox.wxss

/* 复选框组件是公共组件 */
/* 以后需要再多个页面或者需要再多个项目中进行使用 */
/* 所以呢,需要先给复选框组件准备、设置一些默认样式 */
/* 如果在其他页面或者其他项目中使用的时候,发现样式不符合产品需求 */
/* 可以进行修改、对默认的样式进行修改 */

/* 1. 需要给复选框设置默认样式 */
/* 需要先找到小程序给复选框提供的类名,通过小程序给提供的类名修改才可以 */
/* 需要先打开小程序开发文档,找到复选框文档,审查元素,进行查找 */

/* 在自定义组件中,不能直接修改复选框样式 */
/* 如果需要进行修改,需要设置 styleIsolation 才可以 */
/* shared:修改其他页面的样式、组件使用者的样式、以及其他使用了 share 以及 apply-share 的组件 */
/* 这时候,不是想要的结果 */
/* 需求是:只想影响当前组件,可以添加命名空间 */

/* 复选框没有选中时默认的样式 */
.custom-checkbox .wx-checkbox-input {
  width: 24rpx !important;
  height: 24rpx !important;
  border-radius: 50% !important;
  border: 1px solid #fda007 !important;
  margin-top: -6rpx;
}

/* 复选框选中时默认的样式 */
.custom-checkbox .wx-checkbox-input-checked {
  background-color: #fda007 !important;
}

/* 复选框选中时 √ 样式 */
.custom-checkbox .wx-checkbox-input.wx-checkbox-input-checked:before {
  font-size: 22rpx;
  color: #fff;
}

/* 2. 组件使用者也能够修改默认的样式 */

➡️ components/custom-checkbox/custom-checkbox.js

Component({

  options: {
    styleIsolation: 'shared'
  }
  
})

➡️ index.wxss

/* 组件使用者修改复选框的样式 */
.custom .custom-checkbox .wx-checkbox-input {
  border: 1px solid lightseagreen !important;
}

.custom .custom-checkbox .wx-checkbox-input-checked {
  background-color: lightseagreen !important;
}

8. 数据监听器

知识点:

数据监听器可以用于监听和响应任何属性和数据字段的变化,有时,需要在一些数据字段被 setData 设置时,需要执行一些操作。那么就可以使用 observers 数据监听器来实现。语法如下:

Component({
  data: {
    num: 10,
    count: 1,
    obj: { name: 'Tom', age: 10 },
    arr: [1, 2, 3]
  },
  observers: {
    // key 是需要检测数据
    // value 是一个函数,函数接收一个形参作为参数,是最新的值
    num: function(newNum) {
      console.log(newNum)
    },
    
    // 数据监听器支持监听属性或内部数据的变化,可以同时监听多个
    'num, count': function (newNum, newCount) {
       console.log(newNum, newCount)
    }
    
    // 监听器可以监听子数据字段
    'obj.age': function(newAge) {
      console.log(newAge)
    },
    
    // 如果需要监听所有子数据字段的变化,可以使用通配符 ** 
    'obj.**': function(newAge) {
      console.log(newAge)
    },
        
    'arr[0]': function (val) {}
  }
})

9. 组件间通信与事件

9.1 父往子传值

知识点:

父组件如果需要向子组件传递指定属性的数据,在 WXML 中需要使用数据绑定的方式

与普通的 WXML 模板类似,使用数据绑定,这样就可以向子组件的属性传递动态数据。

父组件如果需要向子组件传递数据,只需要两个步骤:

1.在父组件 WXML 中使用 数据绑定 的方式向子组件传递动态数据

2.子组件内部使用 properties 接收父组件传递的数据即可

知识点代码:

<!-- 引用组件的页面模板 -->
<view>
  <costom prop-a="{{ name }}" prop-b="{{ age }}" />
</view>

在组件内部,需要在 Component 构造器中通过 properties 接收传递的数据,接收方式有两种:

Component({
  /**
   * 组件的属性列表 props
   */
  properties: {
    propA: {
      type: String, // 传递的数据类型
      value: '' // 默认值
    },
    propB: Number // 简化的定义方式
  },

  // coding...
})

在子组件中也可以通过 this.setData()properties 中的数据进行修改,但是一般不建议修改

// components/custom01/custom01.js
Component({

  /**
   * 组件的方法列表
   */
  methods: {
    // 修改列表中的数据
    updateProp () {
      this.setData({
        propB: this.properties.propB + 1
      })
    }
  }
})

复选框组件案例:

➡️ index.js

Page({

  data: {
    isChecked: true
  },
    
  // coding...

})

➡️ index.wxml

<custom-checkbox
  label="我已阅读并同意 用户协议 和 隐私协议"
  position="right"
+   checked="{{ isChecked }}">
  我已阅读并同意 用户协议 和 隐私协议 - 111
</custom-checkbox>

➡️ components/custom-checkbox/custom-checkbox.js

Component({

  options: {
    styleIsolation: 'shared'
  },

  properties: {
    
    // coding...

    // 复选框组件公共组件
    // 需要再多个页面、在多个项目中进行使用
    // 在使用的时候,有的地方希望默认是选中的效果,有的地方希望默认是没有被选中的效果
    // 怎么处理 ?
    // 首先让复选框默认还是没有被选中的效果
    // 如果希望复选框默认被选中,这时候传递属性(checked=true)到复选框组件
+     checked: {
+       type: Boolean,
+       value: false
+     }
  },

  /**
   * 组件的初始数据:用来定义当前组件内部所需要使用的数据
   */
  data: {
    isChecked: false
  },

+   observers: {
+     // 如果需要将 properties 中的数据赋值给 data
+     // 可以使用 observers 进行处理
+     checked: function (newChecked) {
+       // console.log(newChecked)
+       this.setData({
+         isChecked: newChecked
+       })
+     }
+   },

  /**
   * 组件的方法列表:在组件中,所有的事件处理程序都需要写到 methods 方法中
   */
  methods: {
    
    // 更新复选框的状态
    updateChecked () {

      this.setData({
+         isChecked: !this.data.isChecked,
+         // checked: !this.properties.checked
        // label: '在组件内部也可以修改 properties 中的数据'
      })

      // 在 JS 中可以访问和获取 properties 中的数据
      // 但是一般情况下,不建议修改,因为会造成数据流的混乱
      // console.log(this.properties.label)
      // console.log(this.data.isChecked)
    }

  }
  
})

➡️ components/custom-checkbox/custom-checkbox.wxml

<!--components/custom-checkbox/custom-checkbox.wxml-->
<!-- <text>我是自定义组件</text> -->

<view class="custom-checkbox-container">
  <view class="custom-checkbox-box {{ position === 'right' ? 'right' : 'left' }}">
+     <checkbox class="custom-checkbox" checked="{{ isChecked }}" bindtap="updateChecked" />

    <view class="content">
      <!-- lable 和 子节点内容都进行了展示 -->
      <!-- 要么展示 lable 要么展示 子节点内容 -->
      <!-- 如果用户传递了 lable 属性,就展示 lable -->
      <!-- 如果用户没有传递 lable 属性,就展示 子节点内容 -->
      <text wx:if="{{ label !== '' }}">{{ label }}</text>

      <slot wx:else />
    </view>
  </view>
</view>

9.2 子往父传值

子组件如果需要向父组件传递数据,可以通过小程序提供的事件系统实现传递传递,可以传递任意数据。

事件系统是组件间通信的主要方式之一,自定义组件可以触发任意的事件,引用组件的页面可以监听这些事件,流程如下:

  1. 自定义组件触发事件时,需要使用 triggerEvent 方法发射一个自定义的事件
  2. 自定义组件标签上通过 bind 方法监听发射的事件

触发事件:

<!-- 在自定义组件中 -->
<button type="primary" plain bindtap="sendData">传递数据</button>
// components/custom05/custom05.js
Component({

  // 组件的初始数据
  data: {
    num: 666
  },

  // 组件的方法列表
  methods: {

    // 将数据传递给父组件
    sendData () {

      // 如果需要将数据传递给父组件
      // 需要使用 triggerEvent 发射自定义事件
      // 第二个参数,是携带的参数
      this.triggerEvent('myevent', this.data.num)
      
    }

  }
})

监听事件:

<view>{{ num }}</view>
<!-- 需要在自定义组件标签上通过 bind 方法绑定自定义事件,同时绑定事件处理函数 -->
<custom05 bind:myevent="getData" />
Page({

  data: {
    num: ''
  },

  getData (event) {
    // 可以通过事件对象.detail 获取子组件传递给父组件的数据
    // console.log(event)
    this.setData({
      num: event.detail
    })
  }

})

复选框组件案例:

➡️ components/custom-checkbox/custom-checkbox.js

Component({

  /**
   * 组件的方法列表:在组件中,所有的事件处理程序都需要写到 methods 方法中
   */
  methods: {
    
    // 更新复选框的状态
    updateChecked () {

      this.setData({
        isChecked: !this.data.isChecked,
        // label: '在组件内部也可以修改 properties 中的数据'
      })

      // 在 JS 中可以访问和获取 properties 中的数据
      // 但是一般情况下,不建议修改,因为会造成数据流的混乱
      // console.log(this.properties.label)
      // console.log(this.data.isChecked)

+       // 目前复选框组件的状态是存储在复选框组件内部的、存储在自定义组件内部的
+       // 但是,在以后实际开发中,组件使用者、父组件有时候也需要获取到复选框内部的状态
+       // 怎么办 ?
+       // 这时候,自定义组件内部就需要发射一个自定义事件,
+       // 如果组件使用者、父组件需要使用数据,绑定自定义事件进行获取即可
+       this.triggerEvent('changechecked', this.data.isChecked)
    }

  }
  
})

➡️ index.html

<custom-checkbox
  label="我已阅读并同意 用户协议 和 隐私协议"
  position="right"
  checked="{{ isChecked }}"
  class="getchild"
+  bind:changechecked="getData"
>
  我已阅读并同意 用户协议 和 隐私协议 - 111
</custom-checkbox>

➡️ index.js

Page({

  data: {
    isChecked: true
  },

  getData (event) {
    console.log(event.detail)

    if (event.detail) {
      console.log('提交')
    } else {
      console.log('请同意协议!')
    }
  }

})
9.3 获取组件实例

如果前面两种方式不足以满足需要。

可在父组件里调用 this.selectComponent() ,获取子组件的实例对象,就可以直接拿到子组件的任意数据和方法。调用时需要传入一个匹配选择器 selector,如:this.selectComponent(".my-component")

<!-- 父组件 -->
<costom bind:myevent="getData" class="custom" />
<button bindtap="getChildComponent"></button>
// 父组件
Page({
  data: {},
  getChildComponent: function () {
    const child = this.selectComponent('.custom')
    console.log(child)
  }
})

复选框组件案例:

➡️ index.html

<custom-checkbox
  label="我已阅读并同意 用户协议 和 隐私协议"
  position="right"
  checked="{{ isChecked }}"
+   class="child"
+  id="child"
  bind:changechecked="getData"
>
  我已阅读并同意 用户协议 和 隐私协议 - 111
</custom-checkbox>

<button type="primary" plain bindtap="getChild">获取子组件实例对象</button>

➡️ index.js

Page({

  // coding...

  // 获取子组件的实例对象
  getChild () {

    // this.selectComponent 方法获取子组件实例对象
    // 获取到实例对象以后,就能获取子组件所有的数据、也能调用子组件的方法
    const res = this.selectComponent('#child')
    console.log(res.data.isChecked)

  }

})

10. 组件生命周期

组件的生命周期:指的是组件自身的一些钩子函数,这些函数在特定的时间节点时被自动触发

组件的生命周期函数需要在 lifetimes 字段内进行声明

最重要的生命周期是 created attached detached 包含一个组件生命周期流程的最主要时间点

定义段描述
created在组件实例刚刚被创建时执行,注意此时不能调用 setData (还没有对模板解析)
attached在组件实例进入页面节点树时执行 (模板已经解析完毕,并且挂载到页面上)
ready在组件布局完成后执行
moved在组件实例被移动到节点树另一个位置时执行
detached在组件实例被从页面节点树移除时执行 (组件被销毁了)
在这里插入图片描述
  1. 【组件实例刚刚被创建好时】, created 生命周期被触发。此时,组件数据 this.data 就是在 Component 构造器中定义的数据 data此时还不能调用 setData 通常情况下,这个生命周期只应该用于给组件 this 添加一些自定义属性字段。

  2. 【在组件完全初始化完毕】、进入页面节点树后, attached 生命周期被触发。此时, this.data 已被初始化为组件的当前值。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。

  3. 【在组件离开页面节点树后】, detached 生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则 detached 会被触发。

Component({
  
  lifetimes: {
    created: function () {
      // 在组件实例刚刚被创建时执行,注意此时不能调用 setData 
      // 一般用来为组件添加一些自定义属性字段。
    },
    attached: function() {
      // attached 在组件完全初始化完毕、进入页面节点树后执行
      // 模板已经解析完毕,并且挂载到页面上
      // 一般都是在这里写对应的交互
    },
    detached: function() {
      // 在组件实例被从页面节点树移除时执行
    },
    
    // coding...
  }
    
  // coding...
})

11. 组件所在页面的生命周期

组件还有一些特殊的生命周期,这类生命周期和组件没有很强的关联

主要用于组件内部监听父组件的展示、隐藏状态,从而方便组件内部执行一些业务逻辑的处理

组件所在页面的生命周期有 4 个: show、 hide、 resize、 routeDone,需要在 pageLifetimes 字段内进行声明
在这里插入图片描述

// components/custom06/custom06.js
Component({

  // coding...

  // 组件所在页面的生命周期
  pageLifetimes: {

    // 监听组件所在的页面展示(后台切前台)状态
    show () {
      console.log('组件所在的页面被展示')
    },

    // 监听组件所在的页面隐藏(前台切后台、点击 tabBar)状态
    hide () {
      console.log('组件所在的页面被隐藏')
    }

  }

})

12. 小程序生命周期总结

小程序冷启动,钩子函数执行的顺序

保留当前页面(navigate) 以及 关闭当前页面(redirect)

切后台 以及 切前台(热启动)

13. 拓展:使用 Component 构造页面

Component 方法用于创建自定义组件

小程序的页面也可以视为自定义组件,因此页面也可以使用 Component 方法进行创建,从而实现复杂的页面逻辑开发

📌 注意事项:

  1. 要求对应 json 文件中包含 usingComponents 定义段

  2. 页面使用 Component 构造器创建,需要定义与普通组件一样的字段与实例方法

  3. 页面 Page 中的一些生命周期方法(如 onLoad() 等以“on”开头的方法),在 Component 中要写在 methods 属性中才能生效

  4. 组件的属性 Properties 可以用于接收页面的参数,在 onLoad() 中可以通过 this.data 拿到对应的页面参数

落地代码:

Component({

  // 为什么需要使用 Component 方法进行构造页面
  // Component 方法功能比 Page 方法强大很多
  // 如果使用 Component 方法构造页面,可以实现更加复杂的页面逻辑开发

  // 小程序页面也可以使用 Component 方法进行构造
  // 注意事项:
  // 1. 要求 .json 文件中必须包含 usingComponents 字段
  // 2. 里面的配置项需要和 Component 中的配置项保持一致
  // 3. 页面中 Page 方法有一些钩子函数、事件监听方法,这些钩子函数、事件监听方法必须方法 methods 对象中
  // 4. 组件的属性 properties 也可以接受页面的参数,在 onLoad 钩子函数中可以通过 this.data 进行获取

  properties: {
    id: String,
    title: String
  },

  data: {
    name: 'tom'
  },

  // onLoad () {
  //   console.log('页面加载 - 1')
  // },

  methods: {

    // 更新 name
    updateName() {
      this.setData({
        name: 'jerry'
      })
    },

    onLoad (options) {
      // console.log('页面加载 - 2')
      // console.log(options)
      console.log(this.data.id)
      console.log(this.data.title)
      console.log(this.properties.id)
    },

  }

})

14. 拓展:behaviors

小程序的 behaviors 方法是一种代码复用的方式,可以将一些通用的逻辑和方法提取出来,然后在多个组件中复用,从而减少代码冗余,提高代码的可维护性。

如果需要 behavior 复用代码,需要使用 Behavior() 方法,每个 behavior 可以包含一组属性、数据、生命周期函数和方法

组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。

注册 behavior:

如果需要注册一个 behavior,需要借助 Behavior() 方法,接受一个 Object 类型的参数

// my-behavior.js

module.exports = Behavior({
  behaviors: [],
  properties: {
    myBehaviorProperty: {
      type: String
    }
  },
  data: {
    myBehaviorData: 'my-behavior-data'
  },
  created: function () {
    console.log('[my-behavior] created')
  },
  attached: function () {
    console.log('[my-behavior] attached')
  },
  ready: function () {
    console.log('[my-behavior] ready')
  },

  methods: {
    myBehaviorMethod: function () {
      console.log('[my-behavior] log by myBehaviorMehtod')
    },
  }
})

使用 behavior:

// my-component.js
const myBehavior = require('my-behavior')

Component({
  behaviors: [myBehavior]
  
  // coding...
})

组件和它引用的 behavior 中可以包含同名的字段,对这些字段的处理方法如下:

  1. 如果有同名的属性或方法,采用 “就近原则”,组件会覆盖 behavior 中的同名属性或方法

  2. 如果有同名的数据字段且都是对象类型,会进行对象合并,其余情况会 采用 “就近原则” 进行数据覆盖

  3. 生命周期函数和 observers 不会相互覆盖,会是在对应触发时机被逐个调用,也就是都会被执行

详细的规则:同名字段的覆盖和组合规则

15. 拓展:外部样式类

默认情况下,组件和组件使用者之间如果存在相同的类名不会相互影响,组件使用者如果想修改组件的样式,需要就解除样式隔离,但是解除样式隔离以后,在极端情况下,会产生样式冲突、CSS 嵌套太深等问题,从而给我们的开发带来一定的麻烦。

外部样式类:在使用组件时,组件使用者可以给组件传入 CSS 类名,通过传入的类名修改组件的样式。

如果需要使用外部样式类修改组件的样式,在 Component 中需要用 externalClasses 定义若干个外部样式类。

外部样式类的使用步骤:

1.在 Component 中用 externalClasses 定义段定义若干个外部样式类

2.自定义组件标签通过 属性绑定 的方式提供一个样式类,属性是 externalClasses 定义的元素,属性值是传递的类名

3.将接受到的样式类用于自定义组件内部

📌注意事项:

​ 在同一个节点上使用普通样式类和外部样式类时,两个类的优先级是未定义的

​ 因此需要添加 !important 以保证外部样式类的优先级

落地代码:

➡️ custom09.js

// components/custom09/custom09.js
Component({

  // 组件接受的外部样式类
  externalClasses: ['extend-class']
})

➡️ custom09.wxml

<!-- 在同一个节点上,如果存在外部样式类 和 普通的样式类 -->
<!-- 两个类的优先级是未定义的 -->
<!-- 建议:在使用外部样式类的时,样式需要通过 !important 添加权重 -->
<view class="extend-class box">通过外部样式类修改组件的样式</view>

➡️ custom09.wxss

.box {
  color: lightseagreen;
}

➡️ profile.wxml

<!-- 属性是在 externalClasses 里面定义的元素 -->
<!-- 属性值必须是一个类名 -->
<custom09 extend-class="my-class" />

➡️ profile.wxss

/* pages/index/index.wxss */

.my-class {
  color: lightsalmon !important;
}

16. 完善复选框案例并总结自定义组件

总结自定义组件:

  1. 组件基本使用:数据、属性、方法、插槽

  2. 组件样式使用:组件样式、注意事项、样式隔离、外部样式类

  3. 组件通信传值:父往子传值、子往父传值、获取组件实例

  4. 组件生命周期:组件的生命周期、组件所在页面的生命周期、总结了小程序全部的生命周期

  5. 组件数据监听器:observers

  6. 组件拓展:使用 Component 构造页面、组件复用机制 behaviors 等

完善复选框案例

➡️ components/custom-checkbox/custom-checkbox.wxml

<!--components/custom-checkbox/custom-checkbox.wxml-->
<!-- <text>我是自定义组件</text> -->

<view class="custom-checkbox-container">
  <view class="custom-checkbox-box {{ position === 'right' ? 'right' : 'left' }}">
+    <label class="custom-label">
      <checkbox class="custom-checkbox" checked="{{ isChecked }}" bindtap="updateChecked" />

      <view class="content">
        <!-- lable 和 子节点内容都进行了展示 -->
        <!-- 要么展示 lable 要么展示 子节点内容 -->
        <!-- 如果用户传递了 lable 属性,就展示 lable -->
        <!-- 如果用户没有传递 lable 属性,就展示 子节点内容 -->
        <text wx:if="{{ label !== '' }}">{{ label }}</text>

        <slot wx:else />
      </view>
+    </label>
  </view>
</view>

➡️ components/custom-checkbox/custom-checkbox.wxss

+ .custom-checkbox-box .custom-label {
  display: flex;
  align-items: center;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1481894.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数通HCIE和云计算HCIE哪个好一点?

数通是网络的基础知识&#xff0c;也是入门人员必学的方向&#xff0c;相对也会简单些&#xff0c;学习数通&#xff0c;可以很好的学习其他的方向。数通的就业范围也比较广&#xff0c;运营商、企业、政府还是互联网公司&#xff0c;都需要大量的数通工程师来搭建和维护网络&a…

Sora引发安全新挑战

文章目录 前言一、如何看待Sora二、Sora加剧“深度伪造”忧虑三、Sora无法区分对错四、滥用导致的安全危机五、Sora面临的安全挑战总结前言 今年2月,美国人工智能巨头企业OpenAI再推行业爆款Sora,将之前ChatGPT以图文为主的生成式内容全面扩大到视频领域,引发了全球热议,这…

MATLAB练习题:排队论问题的模拟

​讲解视频&#xff1a;可以在bilibili搜索《MATLAB教程新手入门篇——数学建模清风主讲》。​ MATLAB教程新手入门篇&#xff08;数学建模清风主讲&#xff0c;适合零基础同学观看&#xff09;_哔哩哔哩_bilibili 下面我们来看一道排队论的题目。假设某银行工作时间内只有一个…

生成式人工智能治理:入门的基本技巧

GenAI 以前所未有的速度调解并扰乱了“一切照旧”&#xff0c;同时带来了令人难以置信的力量&#xff0c;但也带来了不可否认的责任。当然&#xff0c;现代企业非常熟悉技术进步。然而&#xff0c;人工智能的到来&#xff08;和实施&#xff09;无疑引起了相当大的冲击&#xf…

性能优化篇(二) 静态合批步骤与所有注意事项\游戏运行时使用代码启动静态合批

静态合批步骤: 1.开启Project Settings —>Player–>Other Setting里勾选Static Batching选项(一般情况下unity都是默认勾选状态) 2.勾选需要合批的静态物体上的Batching Static项,勾选后此物体下的所有子物体都默认参与静态合批(勾选后物体不能进行移动/旋转/缩放操作,…

Zookeeper4:Java客户端、应用场景以及实现、第三方客户端curator工具包

文章目录 Java连接Zookeeper服务端依赖代码使用 应用场景统一命名服务统一配置管理统一集群管理服务器节点动态上下线理解实现模拟服务提供者【客户端代码】-注册服务模拟服务消费者【客户端代码】-获取服务信息进行请求消费 软负载均衡分布式锁理解实现 生产集群安装N台机器合…

事务Transaction简写为tx的原因

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl Transaction简写的由来 数据库事务Transaction通常被简写为tx。让人疑惑的是&#xff1a;这个单词本身没有字母x为何又将其简写成了tx呢&#xff1f; 第一种可能 Transac…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:背景设置)

设置组件的背景样式。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 background10 background(builder: CustomBuilder, options?: { align?: Alignment }) 设置组件背景。 系统能力&#xff1a; …

java 正则表达式介绍

Java正则表达式是一种强大的文本处理工具&#xff0c;它允许你进行模式匹配、搜索和文本操作。正则表达式提供了一种简洁、灵活的方式来处理字符串&#xff0c;可以用于各种应用场景&#xff0c;如数据验证、文本解析、搜索和替换等。 正则表达式的基础知识 正则表达式…

PaddleOCR 高精度文字识别:丰富多样的前沿算法 | 开源日报 No.187

PaddlePaddle/PaddleOCR Stars: 34.1k License: Apache-2.0 PaddleOCR 是一个丰富、领先和实用的 OCR 工具库&#xff0c;旨在帮助开发者训练更好的模型并将其应用到实际场景中。该项目具有以下特点和优势&#xff1a; 支持多种 OCR 相关前沿算法提供产业级特色模型 PP-OCR、…

CentOS系统上安装幻兽帕鲁/Palworld服务端的详细步骤是什么?

CentOS系统上安装幻兽帕鲁/Palworld服务端的详细步骤是什么&#xff1f; 首先&#xff0c;需要确认Docker是否已经安装。如果未安装&#xff0c;则需要进行安装。接下来&#xff0c;运行Docker容器。这一步是为了创建一个可以运行幻兽帕鲁服务端的环境。然后&#xff0c;在容器…

顺序表基础

⽬录 1. 课前准备 2. 顺序表概念及结构 3. 顺序表分类 4. 实现动态顺序表 正⽂开始 课前预备 1. 课程⽬标 C语⾔语法基础到数据结构与算法&#xff0c;前⾯已经掌握并具备了扎实的C语⾔基础&#xff0c;为什么要学习数据结构 课程&#xff1f;⸺通讯录项⽬ 2. 需要…

AGI概念与实现

AGI AGI&#xff08;Artificial General Intelligence&#xff09;&#xff0c;中文名为“通用人工智能”或“强人工智能”&#xff0c;是指通过机器学习和数据分析等技术&#xff0c;使计算机具有类似于人类的认知和学习能力的技术. 多模态的大模型 &#xff08;Multimodal…

CSS【详解】居中对齐 (水平居中 vs 垂直居中)

水平居中 内部块级元素的宽度要小于容器(父元素) 方案一&#xff1a;文本居中对齐&#xff08;内联元素&#xff09; 限制条件&#xff1a;仅用于内联元素 display:inline 和 display: inline-block; 给容器添加样式 text-align:center<!DOCTYPE html> <html lang&q…

Linux UnixODBC安装配置

配置 UnixODBC 梦之上关注IP属地: 香港 0.2322020.12.09 13:23:10字数 1,202阅读 5,447 麒麟&达梦适配系列: 1.麒麟服务器上安装 DM8 2.配置 UnixODBC 3.beego-ORM 适配达梦 资源紧张的时候&#xff0c;服务器是大家共用的&#xff0c;上面部署了一堆服务。所以选用doc…

【系统分析师】-系统配置与性能评价

1、性能指标 主频&#xff1a;又称时钟频率&#xff0c;1GHZ表示1秒有1G个时钟周期 1s10^9ns 主频外频 * 倍频 时钟周期 主频的倒数指令周期&#xff1a;取出并执行一条指令的时间 总线周期&#xff1a;一个访存储器或IO操作所用时间平均执行周期数&#xff1a;CPI表示…

电机应用-正点原子直流有刷电机例程笔记

目录 基础驱动实验&#xff1a;调速和换向 初始化工作 电机基础驱动API 电压、电流、温度检测实验 初始化工作 采集工作 编码器测速实验 编码器接口计数原理 初始化工作 编码器测速工作 速度环控制实现 PID相关函数 PID运算 电流环控制实现 PID相关函数 PID运算…

CryoEM - CryoAI: Amortized Inference of Poses 工程源码复现

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/136384544 Paper: CryoAI: Amortized Inference of Poses for Ab Initio Reconstruction of 3D Molecular Volumes from Real Cryo-EM Images CryoAI: 基于摊…

【python】双十一美妆数据分析可视化 [聚类分析/线性回归/支持向量机](代码+报告)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

初始Tomcat(Tomcat的基础介绍)

目录 一、Tomcat的基本介绍 1、Tomcat是什么&#xff1f; 2、Tomcat的配置文件详解 3、Tomcat的构成组件 4、Tomcat的顶层架构 5、Tomcat的核心功能 6、Tomcat的请求过程 一、Tomcat的基本介绍 1、Tomcat是什么&#xff1f; Tomcat 服务器是一个免费的开放源代码的Web …