Home Stimulus - 使用外部资源
Post
Cancel

Stimulus - 使用外部资源

上一章节介绍了如何使用值加载和保存控制器的内部状态。但是有时候控制器需要跟踪外部资源的状态,这里的外部资源是指任何不在 DOMStimulus 中的内容。例如,发出 HTTP 请求并在请求状态发生变化时做出响应,或者启动一个计时器,并在控制器断开连接时停止它。

异步加载 HTML

Basecamp 初始页面通过加载和插入远程 HTML 片段异步填充的方式保证页面加载速度,并使视图不受用户特定内容的影响,以便更有效率地进行缓存。

首先构建一个通用内容加载器控制器,该控制器使用从服务器获取的 HTML 填充其元素。然后使用它加载未读消息列表,就像在电子邮件收件箱中看到的那样。

创建 public/index.html 文件:

1
2
3
<div data-controller="content-loader"
    data-content-loader-url-value="/messages.html">
</div>

然后创建消息列表的 public/messages.html 文件:

1
2
3
4
<ol>
  <li>New Message: Stimulus Launch Party</li>
  <li>Overdue: Finish Stimulus 1.0</li>
</ol>

真实的应用程序中,在服务器上动态生成此 HTML,但出于演示目的,这里仅使用静态文件。

实现控制器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static values = { url: String }

  connect() {
    this.load()
  }

  load() {
    fetch(this.urlValue)
      .then(response => response.text())
      .then(html => this.element.innerHTML = html)
  }
}

当控制器连接时,向元素的 data-content-loader-url-value 属性中指定的 URL 发起 Fetch 请求。然后将返回的 HTML 分配给元素的 innerHTML 属性来加载页面。

在浏览器的开发者控制台中打开网络选项卡并重新加载页面,将看到一个代表初始页面加载的请求,然后是控制器对 messages.html 的请求。

使用定时器自动刷新页面

改进控制器,使其可以定期刷新收件箱来保持最新状态。

使用 data-content-loader-refresh-interval-value 属性指定刷新频率(以毫秒为单位):

1
2
3
4
<div data-controller="content-loader"
    data-content-loader-url-value="/messages.html"
    data-content-loader-refresh-interval-value="5000">
</div>

现在更新控制器来检查时间间隔,如果存在,则启动刷新计时器。

向控制器添加静态值定义,并定义新方法 startRefreshing()

1
2
3
4
5
6
7
8
9
10
11
export default class extends Controller {
  static values = { url: String, refreshInterval: Number }

  startRefreshing() {
    setInterval(() => {
      this.load()
    }, this.refreshIntervalValue)
  }

  // …
}

然后更新 connect() 方法,当存在间隔值时调用 startRefreshing()

1
2
3
4
5
6
7
  connect() {
    this.load()

    if (this.hasRefreshIntervalValue) {
      this.startRefreshing()
    }
  }

重新加载页面,在开发者控制台中会看到每五秒会有一次新请求。然后修改 public/messages.html 并等待它出现在收件箱中。

释放跟踪资源

当控制器连接时计时器会自动启动,但永远不会停止。这意味着如果控制器的元素消失,那么仍将继续在后台发出 HTTP 请求。

可以通过修改 startRefreshing() 方法,保留对计时器的引用来解决这个问题:

1
2
3
4
5
  startRefreshing() {
    this.refreshTimer = setInterval(() => {
      this.load()
    }, this.refreshIntervalValue)
  }

然后添加对应的 stopRefreshing() 方法取消定时器:

1
2
3
4
5
  stopRefreshing() {
    if (this.refreshTimer) {
      clearInterval(this.refreshTimer)
    }
  }

最后,为了让 Stimulus 在控制器断开连接时取消计时器,需要添加一个 disconnect() 方法:

1
2
3
  disconnect() {
    this.stopRefreshing()
  }

现在可以确保内容加载器控制器仅在连接到 DOM 时才会发出请求。

最终的控制器类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static values = { url: String, refreshInterval: Number }

  connect() {
    this.load()

    if (this.hasRefreshIntervalValue) {
      this.startRefreshing()
    }
  }

  disconnect() {
    this.stopRefreshing()
  }

  load() {
    fetch(this.urlValue)
      .then(response => response.text())
      .then(html => this.element.innerHTML = html)
  }

  startRefreshing() {
    this.refreshTimer = setInterval(() => {
      this.load()
    }, this.refreshIntervalValue)
  }

  stopRefreshing() {
    if (this.refreshTimer) {
      clearInterval(this.refreshTimer)
    }
  }
}

使用动作参数

如果想让加载器与多个不同的源一起工作,可以使用动作参数来实现:

1
2
3
4
<div data-controller="content-loader">
  <a href="#" data-content-loader-url-param="/messages.html" data-action="content-loader#load">Messages</a>
  <a href="#" data-content-loader-url-param="/comments.html" data-action="content-loader#load">Comments</a>
</div>

然后通过 load 动作使用这些参数:

1
2
3
4
5
6
7
8
9
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  load({ params }) {
    fetch(params.url)
      .then(response => response.text())
      .then(html => this.element.innerHTML = html)
  }
}

甚至还可以拆分参数来获取 URL

1
2
3
4
5
  load({ params: { url } }) {
    fetch(url)
      .then(response => response.text())
      .then(html => this.element.innerHTML = html)
  }
This post is licensed under CC BY 4.0 by the author.

Stimulus - 状态管理

安装 Stimulus