微信小程序自定义组件

一、前言

随着微信小程序开发复杂度的提升,官方提供的基础组件已无法满足日益增长的业务需求。为了提高代码的复用性、可维护性与开发效率,自定义组件 成为了微信小程序开发中不可或缺的重要技能。

本文将带你从零开始,全面掌握 微信小程序自定义组件的开发流程,包括:

✅ 自定义组件的基本结构
✅ 如何创建与使用组件
✅ 组件与页面之间的通信
✅ 组件间传值(props)
✅ 组件事件绑定与触发(自定义事件)
✅ 实战案例:封装一个可复用的“评分组件”
✅ 常见问题与优化建议

并通过完整代码示例帮助你掌握如何在实际项目中高效使用自定义组件。

二、什么是微信小程序自定义组件?

微信小程序的 自定义组件 是开发者基于官方组件封装的、具有独立结构和功能的 UI 模块,支持在多个页面中复用。它与页面类似,但不能独立显示,必须被嵌套在页面或其他组件中使用。

✅ 自定义组件的优势:

优势描述
提高复用性一次编写,多处使用
提高可维护性修改一处,全局生效
提高开发效率减少重复代码
逻辑与视图分离更清晰的组件化结构

三、自定义组件的基本结构

一个自定义组件通常由以下 4 个文件组成:

components/
└── custom-component/
    ├── component.js
    ├── component.json
    ├── component.wxml
    └── component.wxss

✅ component.json(组件配置)

{
  "component": true
}

必须设置 "component": true,表示这是一个组件。

✅ component.js(组件逻辑)

Component({
  options: {
    multipleSlots: true // 允许使用多个插槽
  },
  properties: {
    // 用于接收父组件传入的值
    title: {
      type: String,
      value: '默认标题'
    }
  },
  data: {
    // 组件内部状态
  },
  methods: {
    // 组件内部方法
  }
});

✅ component.wxml(组件结构)

<view class="component-container">
  <text>{{title}}</text>
</view>

✅ component.wxss(组件样式)

.component-container {
  padding: 20rpx;
  background-color: #f0f0f0;
  border-radius: 8rpx;
}

四、如何在页面中使用自定义组件

✅ 1. 引入组件

在使用组件的页面的 json 文件中引入组件:

{
  "usingComponents": {
    "custom-component": "/components/custom-component/component"
  }
}

✅ 2. 在 WXML 中使用组件

<custom-component title="这是一个自定义组件" />

五、组件通信:传值与事件

✅ 1. 父组件 → 子组件:通过 properties 传值

// 子组件 component.js
properties: {
  name: {
    type: String,
    value: '默认名称'
  }
}
<!-- 父页面使用 -->
<custom-component name="ethan" />

✅ 2. 子组件 → 父组件:通过 triggerEvent 触发事件

// 子组件 component.js
methods: {
  onClick() {
    this.triggerEvent('click', { detail: '按钮被点击了' });
  }
}
<!-- 父页面监听 -->
<custom-component bind:click="handleClick" />
// 父页面 index.js
Page({
  handleClick(e) {
    console.log(e.detail); // 输出:按钮被点击了
  }
});

六、插槽(Slots):组件内容插入

✅ 默认插槽

<!-- 父页面 -->
<custom-component>
  <view>插入的内容</view>
</custom-component>
<!-- 组件 component.wxml -->
<view class="component-container">
  <slot></slot>
</view>

✅ 多插槽

// component.json
{
  "component": true,
  "usingComponents": {}
}
<!-- 组件 component.wxml -->
<view class="component-container">
  <slot name="header"></slot>
  <slot name="body"></slot>
  <slot name="footer"></slot>
</view>
<!-- 父页面使用 -->
<custom-component>
  <view slot="header">头部内容</view>
  <view slot="body">主体内容</view>
  <view slot="footer">底部内容</view>
</custom-component>

七、实战案例:封装一个“评分组件”

✅ 功能描述:

  • 显示星星评分(1~5)
  • 支持用户点击评分
  • 可设置只读模式
  • 支持分数回传给父组件

✅ 目录结构:

components/
└── rating/
    ├── rating.js
    ├── rating.json
    ├── rating.wxml
    └── rating.wxss

✅ rating.js

Component({
  properties: {
    score: {
      type: Number,
      value: 0
    },
    readonly: {
      type: Boolean,
      value: false
    }
  },
  data: {
    stars: []
  },
  observers: {
    'score': function(score) {
      this.setData({
        stars: this.generateStars(score)
      });
    }
  },
  methods: {
    generateStars(score) {
      const full = Math.floor(score);
      const half = score % 1 >= 0.5 ? 1 : 0;
      const empty = 5 - full - half;
      return [...Array(full).fill('full'), ...Array(half).fill('half'), ...Array(empty).fill('empty')];
    },
    onStarClick(e) {
      if (this.data.readonly) return;
      const index = e.currentTarget.dataset.index;
      const newScore = index + 1;
      this.setData({ score: newScore });
      this.triggerEvent('change', { score: newScore });
    }
  }
});

✅ rating.wxml

<view class="rating-container">
  <block wx:for="{{stars}}" wx:key="index">
    <image 
      data-index="{{index}}" 
      src="/images/{{item === 'full' ? 'star-full.png' : item === 'half' ? 'star-half.png' : 'star-empty.png'}}" 
      mode="aspectFit"
      bindtap="onStarClick"
    />
  </block>
</view>

✅ rating.wxss

.rating-container image {
  width: 40rpx;
  height: 40rpx;
  margin-right: 10rpx;
}

✅ 页面使用组件

{
  "usingComponents": {
    "rating-component": "/components/rating/rating"
  }
}
<rating-component score="{{3.5}}" bind:change="onRatingChange" />
Page({
  onRatingChange(e) {
    console.log('评分变化:', e.detail.score);
  }
});

八、常见问题与解决方案

问题原因解决方案
组件不显示未正确引入或路径错误检查 usingComponents 配置
数据未更新未使用 setData组件中使用 setData 更新数据
事件未触发未绑定或拼写错误检查事件名是否一致
插槽内容不显示插槽名不匹配检查 slot 名称是否一致
图片路径错误路径相对位置不对使用绝对路径或检查层级关系

九、总结对比表:组件开发关键点一览

类型内容
组件配置component.json 中设置 "component": true
组件传值properties 接收父组件数据
组件事件triggerEvent 向父组件发送事件
插槽使用<slot> 或具名插槽 <slot name="xxx">
数据更新使用 setData 更新组件内部状态
组件复用可在多个页面中引入并使用
组件通信支持父子双向通信

十、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值