today_ai_weather/app/javascript/controllers/search_controller.js

72 lines
2.3 KiB
JavaScript
Raw Normal View History

// app/javascript/controllers/search_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["input", "clearButton", "spinner", "statusIcon"]
connect() {
this.pendingRequest = null
}
submit() {
clearTimeout(this.timeout)
this.timeout = setTimeout(() => {
// 如果有待处理的请求,则中止它
if (this.pendingRequest) {
this.pendingRequest.abort()
}
const form = this.element
const searchInput = this.inputTarget
const encodedValue = encodeURIComponent(searchInput.value)
// 更新 URL
const url = new URL(window.location)
url.searchParams.set('query', encodedValue)
window.history.pushState({}, '', url)
// 显示加载状态
this.showLoadingState()
// 发送请求
this.pendingRequest = new AbortController()
fetch(form.action + '?' + new URLSearchParams(new FormData(form)), {
headers: {
'Accept': 'text/vnd.turbo-stream.html',
'Turbo-Frame': 'cities_results'
},
signal: this.pendingRequest.signal
})
.then(response => response.text())
.then(html => {
Turbo.renderStreamMessage(html)
})
.catch(error => {
if (error.name === 'AbortError') return
console.error('Search error:', error)
})
.finally(() => {
this.hideLoadingState()
this.pendingRequest = null
})
}, 300)
}
showLoadingState() {
if (this.hasClearButtonTarget) {
this.clearButtonTarget.classList.add('hidden')
}
if (this.hasSpinnerTarget) {
this.spinnerTarget.classList.remove('hidden')
}
}
hideLoadingState() {
if (this.hasClearButtonTarget) {
this.clearButtonTarget.classList.remove('hidden')
}
if (this.hasSpinnerTarget) {
this.spinnerTarget.classList.add('hidden')
}
}
}