我正在编写一个使用两个事件处理程序的Scala.js应用程序:一个用于输入字段的onkeyup
事件,另一个用于按钮的onclick
事件。
两个事件处理程序共享很多常见的编码,但是一旦我尝试将事件处理程序编码优化到一个返回事件处理程序功能的单个函数中,它就会正确编译,但事件不再被困在浏览器。
在函数main
中的以下代码中,btn.onclick
的事件处理程序工作正常,但是cityNameInput.onkeyup
的事件处理程序不再工作。我所做的只是将分配的编码直接复制到事件处理程序中,然后将其放置在返回Function1[dom.Event, _]
的keystrokeHandler
函数中。这可以编译确定,但是onkeyup
事件不再被困在浏览器中。
def keystrokeHandler(userInput: String, responseDiv: dom.Element): Function1[dom.Event,_] =
(e: dom.Event) => {
// The city name must be at least 4 characters long
if (userInput.length > 3) {
responseDiv.innerHTML = ""
val xhr = buildXhrRequest(userInput, searchEndpoint)
xhr.onload = (e: dom.Event) => {
val data: js.Dynamic = js.JSON.parse(xhr.responseText)
// Can any cities be found?
if (data.count == 0)
// Nope, so show error message
responseDiv.appendChild(p(s"Cannot find any city names starting with ${userInput}").render)
else {
// Build a list of weather reports
buildSearchList(data, responseDiv)
}
}
// Send XHR request to OpenWeather
xhr.send()
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Main program
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@JSExport
def main(container: dom.html.Div): Unit = {
container.innerHTML = ""
val cityNameInput = input.render
val btn = button.render
val weatherDiv = div.render
cityNameInput.defaultValue = owmQueryParams.get("q").get
btn.textContent = "Go"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Button onclick event handler
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
btn.onclick = (e: dom.Event) => {
if (cityNameInput.value.length > 3) {
weatherDiv.innerHTML = ""
val xhr = buildXhrRequest(cityNameInput.value, weatherEndpoint)
xhr.onload = (e: dom.Event) => {
val data = js.JSON.parse(xhr.responseText)
// Can the city be found?
if (data.cod == "404")
// Nope, so show error message
weatherDiv.appendChild(p(s"City ${cityNameInput.value} not found").render)
else {
// So first add the div containing both the weather information
// and the empty div that will hold the slippy map.
// This is needed because Leaflet writes the map information to an
// existing DOM element
val report = new WeatherReportBuilder(data)
weatherDiv.appendChild(buildWeatherReport(report, 0))
buildSlippyMap("mapDiv0", report)
}
}
// Send XHR request to OpenWeather
xhr.send()
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Input field onkeyup event handler
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cityNameInput.onkeyup = keystrokeHandler(cityNameInput.value, weatherDiv)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Write HTML to the screen
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
container.appendChild(
div(
h1("Weather Report"),
table(
tr(td("Enter a city name (min 4 characters)"), td(cityNameInput)),
tr(td(), td(style := "text-align: right", btn))
),
weatherDiv
).render
)
}
这里有什么问题?
keystrokeHandler
功能是否应该返回一些特殊的Scala.js事件处理程序类型?还是其他东西?
谢谢
Chris W
我认为问题在这里:
cityNameInput.onkeyup = keystrokeHandler(cityNameInput.value, weatherDiv)
事件处理程序是触发的,但是在创建处理程序时,userInput
被冷冻到cityNameInput.value
,而不是随cityNameInput.value
的当前值而变化。确实,该线等同于
val userInput = cityNameInput.value
cityNameInput.onkeyup = keystrokeHandler(userInput, weatherDiv)
很明显cityNameInput.value
仅评估一次。
相反,您应该将cityNameInput
本身作为keystrokeHandler
的参数,并在匿名函数内访问cityNameInput.value
,以便每次调用函数(处理程序)时都会对其进行评估。