You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails 7.1.2 + StimulusJS:Google Maps加载及控制器事件触发异常

Rails 7.1 + Stimulus:Google Maps 加载间歇性异常解决方案

问题核心

Google Maps API 的google-maps-callback事件每次都触发,但 Stimulus 控制器的initMap方法仅偶尔在 Firefox 执行,Brave 中完全不执行——本质是事件触发时序与 Stimulus 控制器挂载时序不匹配:API 回调事件可能在控制器完成事件绑定之前就已经触发,导致控制器错过事件。

解决方案

1. 修改 Stimulus 控制器,兼容已加载/未加载两种状态

在控制器连接时,先检查 Google Maps 是否已加载完成,直接执行初始化;若未加载,则监听事件并确保只执行一次:

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  connect() {
    console.log('localizators controller connected');
    // 优先检查 API 是否已就绪
    if (window.google?.maps) {
      this.initMap();
    } else {
      // 绑定单次事件监听,避免重复触发
      window.addEventListener("google-maps-callback", this.initMap.bind(this), { once: true });
    }
  }

  initMap() {
    console.log('map init');
    // 在这里编写地图初始化逻辑,例如:
    // const mapElement = document.getElementById('map');
    // this.map = new google.maps.Map(mapElement, {
    //   center: JSON.parse(this.data.get('current-location-value')),
    //   zoom: 12
    // });
  }

  disconnect() {
    // 清理事件监听,防止内存泄漏
    window.removeEventListener("google-maps-callback", this.initMap.bind(this));
  }
}

2. 调整脚本加载时序,降低冲突概率

将 Google Maps 的脚本标签从head移到body标签的末尾,确保 DOM 元素(包括 Stimulus 控制器绑定的容器)先解析完成,再加载 API:

<!-- 在 app/views/layouts/application.html.erb 的 </body> 前添加 -->
<script>
  window.dispatchMapsEvent = function(...args) {
    const event = new CustomEvent("google-maps-callback", { detail: args });
    window.dispatchEvent(event);
  }
</script>

<%= javascript_include_tag "https://maps.googleapis.com/maps/api/js?key=#{Rails.application.credentials.google.api_key}&libraries=places&callback=dispatchMapsEvent",
                          defer: true,
                          async: true,
                          "data-turbolinks-eval": false
%>

3. 验证时序问题(可选排查步骤)

在控制台打印事件触发与控制器连接的时间戳,确认时序是否颠倒:

  • 布局中的脚本:
<script>
  window.dispatchMapsEvent = function(...args) {
    const event = new CustomEvent("google-maps-callback", { detail: args });
    console.log("[Google Maps] Callback triggered at:", new Date().getTime());
    window.dispatchEvent(event);
  }

  window.addEventListener("google-maps-callback", function(event) {
    console.log("[Google Maps] API loaded at:", new Date().getTime());
  })
</script>
  • Stimulus 控制器:
connect() {
  console.log("[Stimulus] Controller connected at:", new Date().getTime());
  // ... 其他逻辑
}

如果 API 加载的时间戳早于控制器连接的时间戳,就坐实时序问题。

4. Turbo 环境下的额外处理

如果使用 Turbo 进行页面导航,Google Maps API 仅会加载一次,后续页面切换时需避免重复初始化:
在initMap方法中添加判断:

initMap() {
  if (this.map) return; // 已初始化则直接返回
  console.log('map init');
  // ... 初始化逻辑
}

内容的提问来源于stack exchange,提问作者Bruno Costanzo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 22:18:10