示例 1
index 页面
// index.json
{
"usingComponents": {
"parent":"/component/parent/parent"
}
}
// index.wxml
<parent />
// index.js 这里使用Component来取代Page构造器生成页面实例。
Component({
lifetimes: {
created() {
console.log("index --> created");
},
attached() {
console.log("index --> attached");
},
},
methods: {
onLoad() {
console.log("index --> onLoad");
},
},
});
parent 组件
//parent.json
{
"usingComponents": {
"son": "/components/son/son"
}
}
//parent.wxml
<son />
//parent.js
Component({
lifetimes: {
created() {
console.log("parent --> created");
},
attached() {
console.log("parent --> attached");
},
},
});
son 组件
//son.json
{
"usingComponents": {}
}
//son.wxml
<test>son</test>
//son.js
Component({
lifetimes: {
created() {
console.log("son --> created");
},
attached() {
console.log("son --> attached");
},
},
});
编译后 控制台打印如下
son --> created
parent --> created
index --> created
index --> attached
parent --> attached
son --> attached
index–>onLoad
小结: 组件建立是由内而外的。页面所有组件都挂载到页面组件后,才由外向内触发每个子组件的 attached 周期。最后触发页面的(最外层组件)onLoad 周期。
值得注意的是每个组件 attached 周期触发时,this.data 数据 可能被上级组件传入多次,导致获取不到首次挂载时的 this.data 对象。对调试等一些情况是不友好。
beforeCreate 和 attach
示例 1 展示了小程序给我们提供的生命周期触发顺序。但缺少一些生命周期。或许是小程序认为那些不重要,我们用不到吧。让我们来补充一下,这对调试、开发插件等情形很有帮助
- 增加 attach 周期 (可用作复杂组件调试场景,相比与 attached 只是触发时机不一样,this.data.fields 是首次挂载数据时的实例数据.而 attached 触发时,由于上级组件传入数据导致实例data中的数据已不是当初的样子了,在应对复杂组件应用的调试时不是很好用)
分别在示例 1 增加 如下代码
<!-- index.wxml 增加 attach 传值-->
<parent attach />
<!-- parent.wxml 增加 attach 传值-->
<son attach />
// parent.js
Component({
//新增
properties: {
attach: Boolean,
},
observers: {
attach() {
console.log("parent --> attach");
},
},
//...省略之前示例1中的代码
});
// son.js
Component({
//新增
properties: {
attach: Boolean,
},
observers: {
attach() {
console.log("son --> attach");
},
},
//...省略之前示例1中的代码
});
控制台打印如下
son --> created
son --> attach
parent --> created
parent --> attach
index --> created
index --> attached
parent --> attached
son --> attached
至此我们有了 attach 生命周期 利用这个周期,我们可以看到组件挂载时 this 上的所有信息,在某写情形下对代码优化,调试带来方便。 稍后我们将它和 beforeCreate 一起封装起来。
- 增加 beforeCreate 周期 (触发时机在实例数据建立之前 this 指向当前配置)
因为 created 周期无法修改实例数据、attached 周期又触发太晚、配置阶段又不能调用函数 。 某些情形下(全局注入等)还是需要 beforeCreate 周期的。
办法是 可以为单个组件添加 或 劫持 Component 全局添加如下 behavior
const beforeCreate = Behavior({
definitionFilter(opt) {
opt.lifetimes?.beforeCreate?.call(opt);
delete opt.lifetimes?.beforeCreate; //删除 避免冲突吧。
},
});
// 全局注入beforeCreate
const originalComponent = Component;
Component = function (options) {
options.behaviors ||= [].push(beforeCreate);
return originalComponent(options);
};
编译后 控制台打印如下
parent --> beforeCreate
son --> beforeCreate
son --> created
parent --> created
index --> created
index --> attached
parent --> attached
son --> attached
index --> onLoad
- 合并 attach 和 beforeCreate
// beforeCreateAndAttach.js
export const beforeCreateAndAttach = Behavior({
definitionFilter(opt) {
//attach 注意这里没有对properties和observers字段中判断是否已经有了attach字段
(opt.properties ||= {}).attach = Boolean;
(opt.observers ||= {}).attach = function () {
delete this.data.attach; // 没什么用了
opt.lifetimes?.attach?.call(this);
};
// beforeCreate
opt.lifetimes?.beforeCreate?.call(opt);
delete opt.lifetimes?.beforeCreate; // 没什么用了
},
});
//全局注入
const originalComponent = Component;
Component = function (options) {
(options.behaviors ||= []).push(beforeCreateAndAttach);
return originalComponent(options);
};
// app.js
import "./beforeCreateAndAttach";
App({});
index --> beforeCreate
parent --> beforeCreate
son --> beforeCreate
son --> created
son --> attach
parent --> created
parent --> attach
index --> created
index --> attached
parent --> attached
son --> attached
index --> onLoad
总结:
-
利用 behavior 中的 definitionFilter,可在组件实例创建前修改原配置。模拟 beforeCreate 生命周期。
-
利用 properties 传 boolean 值,通过 observers 监控传值字段 达到获取组件挂载时第一时间的 this 实例数据,模拟 attach 生命周期。
已知不足是:需要在要调用 attach 生命周期的组件上加入 attach(可自定义)字段, 有可能导致数据字段冲突,但此周期多用于调试,仅当需要调试组件,查看挂载时数据时,手动添加也没什么问题。 -
水平有限,如有错误之处,请留言指教。