provide-inject 跨层通信
收藏
我的收藏

基础库 2.62.0 开始支持。​
provide-inject 是一种允许祖先组件跨多层向后代组件传递内容的通信方式。​
对于层层嵌套的组件,祖先组件可以通过一个 provide 选项来提供数据,后代组件可以通过声明 inject 选项注入(开始使用)这些数据。声明了 inject 选项的组件被称为 inject 组件,为 inject 组件提供数据的祖先组件被称为 provide 组件。provide 组件不需要知道哪些后代组件使用它提供的数据,inject 组件也不需要知道注入的数据来自哪个 provide 组件。​

使用前配置​

默认情况下,provide-inject 能力是关闭的,如果开发者想使用 provide-inject 能力,需要在 app.json 声明以下字段:​
{ "usingProvide": true }
开启 provide-inject 能力前,请检查旧代码,如果在 Page 函数或 Component 函数的参数对象中定义了 provideinjectsetProvide 字段之一或在自定义组件的 methods字段中定义了 setProvide 方法 ,请使用其他的名字替换,除非开发者清楚自己确实正在使用 provide-inject 能力。​

数据提供与数据注入​

假设存在自定义组件 A、B、C 依次嵌套, 结构如下所示。​
A └── B └── C
如果需要将组件 A 的某个数据传给组件 C,只需要分别在组件 A 和 组件 C 声明 provide 选项和 inject 选项,代码如下:​
// 组件 A 的 js Component({ data: { app: "toutiao", }, provide() { // 返回值就是要提供的数据 return { providedA: this.data.app, }; }, }); // 组件 C 的 js Component({ data: { c: "douyin", }, inject: ["providedA"], // 从组件 A 中获取 providedA 的值,即 'toutiao' ready() { this.setData( { c: this.inject.providedA, }, () => { console.log(this.data.c); // 'toutiao } ); }, });

provide 说明​

    provide 作为 Component 函数或 Page 函数的参数对象的一个可选字段使用。​
    provide 类型是 function,返回值是一个数据对象,这个数据对象的 key 就是能被 inject 组件检索的属性名,value 是实际提供的值,可以是任何值。​
    provide 函数的 this 指向组件实例本身,因此在函数体内可以通过 this.datathis.propertiesthis.injectthis 分别访问到自身的数据、属性、注入数据和组件方法 。​
    在组件或页面初始化的时候如果存在 provide 选项并且 provide 选项是一个函数,就会执行 provide 函数。函数的执行时机在自定义组件触发生命周期 created 或页面触发生命周期 load 之前。​

inject 说明​

    inject 作为自定义组件的 Component函数的参数对象的字段使用。​
    inject 声明可以从祖先 provide 组件获取的数据。如果祖先存在多个 provide 组件声明了同一个 key, inject 组件注入此 key 时选择的是最近 provide 组件的 key。​
    inject类型可能是以下其中一种:​
    string[],每个元素表示注入的 key,需要 provide 组件提供同名的 key 才能拿到注入值到 inject 组件中。​
    object,对象的 key 是 inject 组件注入的 key 名,类型为 string | symbol, inject 组件可以通过 this.inject[key] 访问 provide 组件的数据,value 的类型可以是:​
    string | symbol,表示在 provide 组件搜索用的 key。​
    object,有fromdefault两个可选字段,其中:from 是在 provide 组件中搜索用的 key,用于取别名。比如 a: {from: 'b'} 会将 provide 组件的提供的 b 映射到 inject 组件的 this.inject.a 上;default 是在 provide 组件找不到 key 时使用的默认值。可以是任何类型,如果 default 是一个函数,则找不到 key 时,在组件初始化的时候会自动执行 default 函数,函数的返回值作为 this.inject[key] 的值​

数据的更新​

如果需要将组件 A 提供的 providedA 的值更新为其他值, 比如从 this.data.app 更新为 "xigua",可以在 provide 组件中使用 setProvide 函数实现,代码如下:​
<!-- 组件 A 的 ttml --> <button bindtap="methodA">点击更新 provide</button>
// 组件 A 的 js Component({ data: { app: "toutiao", }, provide() { // 返回值就是要提供的数据 return { providedA: this.data.app, }; }, methods: { methodA() { this.setProvide({ providedA: "xigua", }); }, }, }); // 组件 C 的 js Component({ data: { c: "douyin", }, inject: ["providedA"], // 从组件 A 中获取 providedA 的值,即 'toutiao' ready() { this.setData( { c: this.inject.providedA, }, () => { console.log(this.data.c); // 'toutiao } ); }, observers: { // 点击组件 A 的 button 后,触发该监听器的执行 providedA(val) { console.log(val); // 'xigua' console.log(val === this.inject.providedA); // true }, }, });

setProvide 说明​

    setProvide 是 Component 或 Page 实例上的一个方法。​
    setProvide 类型是function,函数参数是一个数据对象,数据对象的 key 是 provide 组件需要被更新的 key,必须是 provide 函数返回对象中已经声明过的 key,setProvide 用于更新 provide 组件向后代 inject 组件提供的数据,可以触发 inject 组件的 对更新字段的监听回调。​
    setProvide 的执行不会触发页面的重新渲染。​

注入的 key 的别名机制​

observers 可以对 this.inject 的字段进行监听,如同对 this.data 的字段监听一样,当 this.inject 的字段和 this.data 的字段重复时,observers 只能监听 this.inject 的字段。inject 组件可以通过给注入的 key 取别名的方式规避 this.inject 的字段和 this.data 的字段重复的问题。代码如下:​
// 组件 A 的 js Component({ data: { app: "toutiao", }, provide() { // 返回值就是要提供的数据 return { providedA: this.data.app, }; }, }); // 组件 C 的 js Component({ inject: { fromProvidedA: "providedA", // 将 providedA 映射成别名 fromProvidedA }, ready() { console.log(this.inject.providedA); // undefined console.log(this.inject.fromProvidedA); // 'toutiao' }, }); // 另一种写法 // 组件 C 的 js Component({ inject: { fromProvidedA: { from: "providedA", // 将 providedA 映射成别名 fromProvidedA }, }, ready() { console.log(this.inject.providedA); // undefined console.log(this.inject.fromProvidedA); // 'toutiao' }, });

注入的 key 的默认值​

如果 inject 组件在 inject 选项声明了一个 key,该 key 无法在任何一个祖先组件中找到,则 this.inject[key]的结果为 undefined。 通过在 inject 选项声明 default 字段的方式,可以在 inject 组件找不到能够提供某个 key 的祖先组件的情况下,将默认值赋给 this.inject[key]。代码如下:​
// 组件 C 的 js Component({ inject: { notExist: { default: "tomato", }, }, ready() { console.log(this.inject.notExist); // 'tomato' }, });
如果 default 字段声明成一个函数,则取 default 函数的返回值作为 this.inject[key] 的默认值, default 函数的 this 指向组件实例自身。​
// 组件 C 的 js Component({ data: { a: 1, }, inject: { notExist: { default() { return this.data.a + 1; }, }, }, ready() { console.log(this.inject.notExist); // 2 }, });