小程序组件化开发深度解析
小程序组件化:自定义组件、WXML/WXSS 隔离、properties/slot 与抽象节点。 讲清组件通信与复用方式,掌握后能答出「小程序组件和页面组件的边界」。
小程序组件化开发深度解析
一句话概括
小程序组件不是 Web Components 的移植——它拥有独立的样式作用域、Component 构造器、relations 联动和抽象节点,是在双线程架构之上重新设计的一套完整组件体系。
核心知识点
1. Component vs Page:本质区别
1
2
3
4
5
6
7
8
9
// Page 和 Component 底层都是 Component 构造器
// Page 是 Component 的一个特殊子类(多了页面生命周期)
// Component 的核心能力:
// ① properties:父组件传入的属性(支持 8 种类型 + observer)
// ② triggerEvent:子组件向父组件发送事件(类似 Vue 的 $emit)
// ③ 样式隔离:默认 isolated,组件间样式互不影响
// ④ 多插槽:<slot name="header"> 按名插入
// ⑤ 组件关系:relations 管理父子/兄弟组件联动
2. 样式隔离的三种模式
1
2
3
4
5
6
7
8
/* isolated(默认):组件内外完全隔离,互相不影响 */
/* apply-shared:页面样式能穿透进组件,但反过来不行 */
/* shared:互相穿透,类似全局 CSS */
/* 如果需要父组件定制子组件样式,用 externalClasses: */
Component({
externalClasses: ['price-class'], // 声明外部样式类
});
1
2
<custom-price price-class="my-red-price" />
<!-- my-red-price 的样式可以穿透到组件根节点上 -->
3. 抽象节点:把”是什么”延迟到运行时决定
1
2
3
4
5
6
7
8
9
10
11
12
// 场景:一个网格容器组件,每个格子里渲染什么不确定
// 有时候是商品卡片,有时候是分类图标
// 组件定义时声明抽象节点:
Component({
abstractNodes: { gridItem: { type: 'component' } }
});
// 使用时再指定具体组件:
// <grid-container generic:grid-item="product-card" />
// <grid-container generic:grid-item="category-icon" />
// 同一个 grid-container 组件,两种完全不同的内容渲染
4. Relations:组件间不需要手动传递的联动
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// form-group 和 form-control 的经典关系
// form-group 需要知道它包含的所有 form-control
// form-control 需要知道它属于哪个 form-group
// relations 自动建立这种双向引用:
Component({
relations: {
'../form-control/form-control': {
type: 'child',
linked(target) { this._controls.push(target); },
unlinked(target) { this._controls = this._controls.filter(c => c !== target); },
},
},
// 现在 form-group.getValues() 可以遍历 this._controls 收集所有子控件的值
});
5. 组件间通信的完整矩阵
1
2
3
4
父 → 子:properties 传值
子 → 父:triggerEvent('change', { value })
兄弟组件:通过父组件中转,或用 relations 直接获取
跨层级:EventChannel / getCurrentPages + selectComponent
其实你每天都在用
- Vant Weapp 的 van-button:点一下有 loading 状态、颜色跟随主题——这背后就是 properties(loading) + triggerEvent(click) + externalClasses
- 微信支付弹窗:弹出层、按钮组、金额显示分别在不同组件中,通过 relations 联动校验
- 转发按钮的 open-type=”share”:这是微信内置组件的能力,你在自定义组件里无法直接使用——因为组件里不能写 open-type
- 小程序插件:第三方提供的组件包,本质上就是提前写好的 Component 定义,你通过 usingComponents 引入即可
常见误解(FAQ)
❌ 误区一:”小程序组件跟 Vue 组件差不多”
一个关键区别:小程序组件不能在 JS 中动态创建。你必须先在模板(WXML/JSON)中声明,然后才能使用。没有 new Component() 或 createComponent() 这样的 JS API。这就是为什么动态表单(按配置渲染不同控件)在小程序中特别难做——必须用 wx:if 穷举。
❌ 误区二:”组件里改 this.data 不写 setData 也行,反正直接改内存”
在逻辑层确实可以改 this.data,但渲染层完全不知道。你会发现组件内部数据”变了”但 UI 不变。这是双线程架构的副作用——没有 setData 就没有跨线程通信,渲染层永远收不到更新。
❌ 误区三:”多插槽就是开个口子让内容进去,性能没影响”
每个 <slot> 在编译时对应一个虚拟节点。如果一个组件声明了 10 个具名插槽但只用 1 个,多余的插槽仍会生成虚拟节点,增加 Diff 开销。使用插槽时按需开启 multipleSlots: true,不需要多插槽时保持关闭。
一句话总结
小程序组件化的核心是”隔离+声明”——样式隔离让你敢在任何页面复用,模板声明让你不能动态创建,这两者加起来塑造了小程序独特的组件开发体验。
本文由作者按照 CC BY 4.0 进行授权