前一篇文章Stimulus 状态管理,幻灯片显示讲述了Stimulus的状态管理,接下来我们看看如何跟踪外部资源的状态。
有时候我们的controllers需要跟踪外部的资源的状态,这里的外部指的是不在DOM或不在Stimulus中的任何东西。例如,我们可能需要发出HTTP请求,并在请求状态变化时进行响应。或者我们希望启动一个定时器,然后当controller断开连接时停止定时器。在本文,我们将解决这些问题。
接下来,我们学习一下,如何通过加载和插入远程HTML片段,来异步填充页面的各个部分。
我们要创建一个通用的用于加载内容的controller,所有的HTML内容都是从服务器获取的。然后我们将用它来加载一系列未读的消息,就像你在邮箱里看到的那样。
打开public/index.html:
<div data-controller="content-loader"
data-content-loader-url-value="/messages.html"></div>
然后创建一个public/messages.html
<ol>
<li>New Message: Stimulus Launch Party</li>
<li>Overdue: Finish Stimulus 1.0</li>
</ol>
在真实应用中,这个内容是服务器动态生成的,但是这里出于示范的目的,我们就用一个静态文件。
现在我们实现一下我们的controller:
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)
}
}
当controller连接元素时,会根据data-content-loader-url-value属性值设置的url,发起请求。然后把请求得到的HTML内容,赋值给连接元素的innerHTML。
打开浏览器的开发者工具,点开网络查看tab页,然后刷新页面。您将看到一个表示初始页面加载的请求,随后是controller对messages.html的后续请求。
我们继续优化一下controller,隔段时间就刷新div内的内容,让它一直显示最新的内容。
我们使用data-content-loader-refresh-interval-value属性值来设定刷新的时间间隔,单位是毫秒,
<div data-controller="content-loader"
data-content-loader-url-value="/messages.html"
data-content-loader-refresh-interval-value="5000"></div>
现在我们修改一下controller,检查间隔,如果间隔值存在,就启动一个定时器来刷新。
在controller里添加一个static values,然后定义一个新方法startRefreshing():
export default class extends Controller {
static values = { url: String, refreshInterval: Number }
startRefreshing() {
setInterval(() => {
this.load()
}, this.refreshIntervalValue)
}
// …
}
然后修改connect()方法,如果refreshInterval值存在的话,就调用startRefreshing()方法。
connect() {
this.load()
if (this.hasRefreshIntervalValue) {
this.startRefreshing()
}
}
刷新页面,然后通过开发者工具,观察一下,是不是每5秒钟就会有一个新请求。然后可以尝试修改public/messages.html,所有的改变都会出现在div内。
当controller连接元素时,我们启动了定时器,但是我们没有停止它。这意味着,如果我们的controller连接的元素消失的话,controller将在后台继续发起HTTP请求。
我们修复这个问题,修改startRefreshing()方法,保存一个对定时器的引用:
startRefreshing() {
this.refreshTimer = setInterval(() => {
this.load()
}, this.refreshIntervalValue)
}
然后添加一个对应的stopRefreshing()方法,来取消定时器:
stopRefreshing() {
if (this.refreshTimer) {
clearInterval(this.refreshTimer)
}
}
最终,我们告诉Stimulus当controller失去连接时,取消定时器,好,我们添加一个disconnect()方法:
disconnect() {
this.stopRefreshing()
}
现在我们可以确定,内容加载器controller只会在连接到DOM时才会发出请求。
我们来看一下最终的controller类:
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)
}
}
}
本文介绍了如何使用Stimulus生命周期回调来获取和释放外部资源。