# trait behaviors
如果一个组件需要暴露一些 JS 接口给另一些组件使用,可以用 methods、export 等方式,但它们都有些这样那样的问题。
现在最推荐的方式是使用 trait behaviors。它可以有效解耦逻辑,并具有很好的 TypeScript 支持。
目前,trait behaviors 只有 glass-easel 组件框架原生支持。想在 exparser 组件框架上使用,可以借助 chaining-api-polyfill 。但需要注意:chaining-api-polyfill 定义的 trait behaviors 只能在由它定义的组件中使用;反之,glass-easel 原生定义 trait behaviors 也只能在 glass-easel 原生定义的组件中使用。
# trait behaviors 基本用法
设计理念上,trait behaviors 主要是配合 TypeScript 类型使用的。因此,以下例子都用 TypeScript 编写。
# 定义 trait behaviors
首先,使用 trait behaviors 定义一组接口。这组接口可以有个 TypeScript 声明。
// 定义一组接口
export interface IFooTrait {
bar(): string
}
// 将 TypeScript 接口定义包装成 trait behavior
export const fooTrait = Behavior.trait<IFooTrait>()
# 实现 trait behaviors
提供接口实现的组件,就需要实现 trait behaviors。实现时,需要使用 Chaining 形式。
export default Component()
.init(function ({ implement }) {
// implement 应在 init 函数返回前调用
// 不应该写在生命周期函数、事件回调函数、其他方法内部
implement(fooTrait, {
bar() {
return 'bar'
},
})
})
.register()
# 调用 trait behaviors 实现
对于已经实现了 trait behaviors 的组件,通过这个组件的 this 可以访问到它的实现。
export default Component()
.init(function ({ implement, lifetime }) {
// 实现 trait behavior
implement(fooTrait, {
bar() {
return 'bar'
},
})
lifetime('attached', () => {
// 获取组件实例 `this` 对 fooTrait 的实现(未实现的话,返回 undefined)
const fooImpl = this.traitBehavior(fooTrait)!
// 可以调用 trait behaviors 中的方法
fooImpl.bar() // 'bar'
})
})
.register()
实践中,更常见的情况是 trait behaviors 配合 组件间关系 或 组件树访问 来一同使用,请参考它们的文档。
# trait behaviors 的扩展方法
trait behaviors 本身可以包含一些扩展方法。这些扩展方法可以基于已有方法扩展出一些新的接口,有时可以用来简化代码。
具体来说,Behavior.trait 可以提供一个转换函数,例如:
// 实现者需要实现的方法
interface IPlusTrait {
plus(a: number, b: number): number
}
// 调用者可以调用的方法
interface IPlusMinusTrait extends IPlusTrait {
minus(a: number, b: number): number
}
// Behavior.trait 可以传递一个转换函数,将实现者实现的 impl 转换为调用者可以获取的对象
export const plusMinusTrait = Behavior.trait<IPlusTrait, IPlusMinusTrait>((impl) => ({
// 添加一些调用者可以调用的方法
minus(a: number, b: number) {
return impl.plus(a, -b)
},
...impl
}))
转换函数也可以裁剪掉一些不暴露给调用者的接口(不完全暴露 ...impl)。