基于类的扩展

如果您的扩展要监听多个事件并跟踪状态,您可能需要考虑将扩展定义为 JavaScript 类。类是创建对象的模板。它封装了数据和对数据进行操作的方法。这种封装有助于使扩展更有条理。我们面临的挑战是如何定义一个类,使其可以作为 Antora 扩展使用。本页将向您展示如何做到这一点。

扩展类结构

基于类的扩展的基本结构如下:

  • 定义一个以扩展命名的类(如 MyExtension)

  • 添加一个 Antora 可以调用的静态注册方法

  • 将监听器定义为实例方法(例如 onPlaybookBuilt ({ playbook })

  • 添加一个构造函数,接受生成器上下文并从类中注册监听器

  • 导出类定义

下面是我们扩展类的骨架:

class MyExtension {
}

让我们来补充一下细节。

注册方法和初始化

Antora 不会为您的类创建实例,但您可以使用类的静态注册方法来创建实例。如果您来自 Java,可以把它想象成类的主方法。下面是该入口点的样子:

class MyExtension {
  static register () {
    new MyExtension(this)
  }
}

module.exports = MyExtension

Antora 将看到的只是导出类定义中的 register 方法,Antora 将调用该方法启动进程。其余工作都在扩展实例中进行。

请注意静态 register 方法是如何将我们从静态函数过渡到扩展类实例的。register 方法将生成器上下文传递给了扩展类的构造函数,这样构造函数就可以访问并存储对生成器上下文的引用。

监听器方法

监听器被定义为扩展类的方法。它们会像其他监听器函数一样被调用,只是会同时引用类的当前实例(this)和生成器上下文(this.context)。这样,它们就可以访问扩展的属性(扩展状态)和生成器中的上下文变量。下面是以方法形式定义监听器的扩展类:

class MyExtension {
  static register () {
    new MyExtension(this)
  }

  onPlaybookBuilt () {
    this.startTime = +new Date
  }

  onSitePublished () {
    const elapsed = (+new Date - this.startTime) / 1000
    const logger = this.context.getLogger('my-extension')
    logger.info(`elapsed time: ${elapsed}s`)
  }
}

module.exports = MyExtension

现在只需将这些监听器连接到事件即可。

构造器和增加监听器

下一步是创建一个构造函数,接受生成器上下文并添加监听器。下面是带有构造函数的扩展类:

class MyExtension {
  static register () {
    new MyExtension(this)
  }

  constructor (generatorContext) {
    ;(this.context = generatorContext)
      .on('playbookBuilt', this.onPlaybookBuilt.bind(this))
      .on('sitePublished', this.onSitePublished.bind(this))
  }

  onPlaybookBuilt () {
    this.startTime = +new Date
  }

  onSitePublished () {
    const elapsed = (+new Date - this.startTime) / 1000
    const logger = this.context.getLogger('my-extension')
    logger.info(`elapsed time: ${elapsed}s`)
  }
}

module.exports = MyExtension

添加每个监听器时,必须将其绑定到扩展实例(即 this)。否则,监听器将无法访问扩展实例上的属性。监听器仍可使用 context 属性访问生成器上下文,构造函数会将生成器上下文分配给该属性。

正如你所看到的,使用基于类的扩展可以使你的扩展代码更有条理。它还允许你的扩展利用其他面向对象的模式,如继承、组合和委托。