12

我正在使用 gmaps4rails 在“客户”显示页面上加载地图。我已经集成了 turbolinks 以使应用程序更加快速,但现在我遇到了一个问题,我必须使用地图刷新页面才能显示地图。我得到的只是一个空白的地图框。当我刷新页面时,地图正确显示。

我尝试添加 gem 'jquery-turbolinks',但问题仍然存在。

鉴于:

<%= gmaps("map_options" => {:container_class => "map_container_renamed", "zoom" => 15, "auto_zoom" => false},"markers" => { "data" => @json }) %>

在 application.js 中

//= require jquery
//= require turbolinks
//= require jquery.turbolinks
//= require jquery_ujs
//= require twitter/bootstrap
//= require_tree .

此处地图为空白的页面来源的要点。

4

6 回答 6

24

修复最终导致我需要加载整个页面才能刷新脚本。

添加

'data-no-turbolink' => true

到地图页面的链接工作。

例如,如果我有一个客户的索引页面,并且我有一张客户在展示页面上所在位置的地图,那么转到展示页面的链接将采用如下格式:

<%= link_to 'View Client', client, class: "btn", 'data-no-turbolink' => true %>

这将导致 html 和 javascript 的完全刷新,而不仅仅是更改的 html。

于 2012-12-11T17:22:40.233 回答
17

技术背景

数据无涡轮链接

请注意,仅将属性添加data-no-turbolink="true"到链接会抑制该链接的 turbolinks。单击该链接会加载整个页面,而不是用 turbolinks 替换内容。

但是有几种方法可以在抑制 turbolink 的情况下将 turbolink 与 gmaps4rails 一起使用。

Turbolinks 回调

使用 turbolinks 的关键是使用提供的回调。在这种情况下,当 turbolinks 加载新页面时,必须告诉 gmaps4rails 执行地图加载。

一般来说,可以使用$(document).on('page:load', function ... ),例如Railscast #390中所示。

JavaScript 的同源策略

gmap4rails gem 包含的google api 脚本从 google 静态服务器请求另一个脚本。但是如果 api 被 turbolinks 动态包含,那么单源策略会阻止对 google 静态服务器的请求。

单源策略本身就是一个有用的东西。尽管有几种方法可以规避它,但这似乎不是一件自然的事情。相反,“正确的方法”是“证明”网页确实想要执行远程脚本(google api)并且远程脚本不是由恶意脚本请求的。这是通过在 html 树中包含直接请求 google api 的脚本标记来完成的。

在使用 turbolinks 时,只有在第一次请求时才能将 google api script 标签直接包含在 html 树中,因为所有以后的更改都是通过 turbolinks 动态注入到树中的。这意味着,当使用 turbolinks 时,即使在不显示地图的页面上也必须包含 google api。

解决方案 1(推荐):为 gmaps4rails 使用 fork

我提出了一个拉取请求,希望为 gmaps4rails 添加 Turbolinks 支持。

演示

如果您愿意,请先看一下这个演示,它显示了 gmaps4rails 与 turbolinks 的使用:

如何在您的项目中使用它

您可以通过将 fork 添加到 Gemfile 来尝试一下并检查它是否适用于您的项目:

# Gemfile
# ...
gem 'turbolinks'
gem 'gmaps4rails', '~> 2.0.1', git: 'https://github.com/fiedl/Google-Maps-for-Rails.git'
# ...

此外,您需要修改布局文件以将 api 包含在 html 头中:

<!-- app/views/layouts/application.html.erb -->
<html>
  <head>
    ...
    <%= stylesheet_link_tag    "application", :media => "all" %>
    <%= javascript_include_tag "application" %>
    <%= gmaps4rails_api_script_tags  #   <-- THIS IS NEW ----------------- %>
    <%= csrf_meta_tags %>
  </head>
  <body>
    ...
    <%= yield %>
    <%= yield :scripts %>
  </body>
</html>

如果由于某种原因你不想使用这个 fork,我看到了两种使用 gmaps4rails 和 turbolinks 的替代方案:

解决方案 2:手动执行

基本上做与fork相同的事情(解决方案1),可以手动将api脚本添加到布局文件的头部。然后,当通过 turbolinks 加载页面时,可以使用 javascript 配置和激活地图。

这通常在 gmaps4rails wiki 中与 UJS 一起使用: https ://github.com/apneadiving/Google-Maps-for-Rails/wiki/Using-with-UJS

解决方案 3:手动包含 api 静态信息

如果您不想全局添加 api 脚本,有一种方法可以绕过单源策略并动态加载 api。

我为此准备了一个要点https ://gist.github.com/fiedl/6573175

您必须添加一个执行两件事的 javascript 文件:

  1. 加载谷歌地图 api本身。
  2. 加载静态文件,该文件由 api 加载。

您可以通过在浏览器中打开api 脚本getScript并从底部的调用中复制 url 来找到静态文件的 url 。

但是:这样做会修复对您的语言环境的静态 api 请求,如果您的应用程序在国际上使用,这可能不是一件好事。

于 2013-03-19T02:19:12.760 回答
5

在重新访问已经由 turbolinks 管理的页面时,我无法填充地图画布,尤其是在使用后退按钮时。我通过为 turbolinks 事件添加一个侦听器page:load来映射初始化来解决此问题。

map.js.coffee

google.maps.event.addDomListener(window, 'load', @_setup)
google.maps.event.addDomListener(window, 'page:load', @_setup)

应用程序.js.coffee

//= require jquery
//= require jquery.turbolinks
于 2013-08-07T01:16:26.553 回答
0

正如可以在这个Github 问题中找到的那样,您可以将 google 脚本包含到您的所有页面中。这解决了 Turbolinks 不为新导航页面执行 gmaps4rails javascripts 的问题。

请注意,gmaps4rails gem 具有javascript 依赖项,即:

<script src="//maps.google.com/maps/api/js?v=3.13&amp;sensor=false&amp;libraries=geometry" type="text/javascript"></script>
<script src='//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js' type='text/javascript'></script>

您通常可以通过编辑将它们添加到所有页面中app/views/layouts/application.html.erb

应用程序.html.erb

....
<head>
...
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
  <%= csrf_meta_tags %>

  # insert the following two lines
  <script src="//maps.google.com/maps/api/js?v=3.13&amp;sensor=false&amp;libraries=geometry" type="text/javascript"></script>
  <script src='//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js' type='text/javascript'></script>

</head>
...

另外,不要忘记通过编辑将源代码添加到您的资产管道app/assets/javascripts/application.js

应用程序.js

添加这个:

//= require gmaps/google

现在,无需刷新页面即可加载地图。

于 2014-10-28T06:17:49.053 回答
0

我遇到了同样的问题,但我不想关闭 turbolinks,而且我无法正确处理 turbolink DOM 侦听器。

在修复另一个问题并重构我的 javascript 时,我偶然解决了这个问题。

这是我的functions.js

var init_map = function (allMarkers) {
handler = Gmaps.build('Google');
handler.buildMap({ provider: {maxZoom:17, minZoom:5}, internal: {id: 'map'}}, function(){
  markers = handler.addMarkers(allMarkers());
  handler.bounds.extendWith(markers);

   handler.fitMapToBounds();
});
};

var marker_check = function(){...};

var init_autocomplete = function () {...};


//function to call google maps functions

var init_google_api = function(function_name){
  $(document).ready(function(){
  google.maps.event.addDomListener(window, "load", function_name );
});
};

因为我也在使用 google places 库,所以我有几个可以用init_google_api()调用的函数

在我想要地图的每个视图中,我只需放置一个

<%= javascript_tag do %>
   init_google_api(init_map(marker_check));
<% end %>

在视图的最后。修复了所有内容 + 保持代码干燥,因为想要不止一张地图等。

如果我没记错的话,这种方法绕过了 turbolink 问题,因为每次调用视图时,它都会执行 init_google_api 函数和作为参数传入的函数(这就是我使用函数表达式的原因)。所以每次调用函数时都会运行代码。

于 2015-03-02T10:50:41.360 回答
0

您可以直接从谷歌地图 URL 使用回调

<script src="https://maps.googleapis.com/maps/api/js
 ?callback=yourInitFunction
 &key=&sensor=false">

但是请注意,您必须在调用此脚本之前定义您的 init 函数。

这是我如何进行的。我有一个助手可以生成 Gmaps 脚本标签,并回调正确的函数(+ 加载其他 gmaps 脚本)

# view/your_view.html.erb
<script>
function onGmapsInit() {
    // Your code here. You can also define this function in your assets/js directly.
}
</script>
<%= gmap_scripts(callback: 'onGmapsInit') %>

还有我的帮手

# helpers/maps_helper.rb
module MapsHelper
  GMAPS_V3_URL = 'https://maps.googleapis.com/maps/api/js'

  def gmap_scripts(options = {})
    callback = options.delete(:callback)
    gmaps_v3_options = {
      src: "#{GMAPS_V3_URL}?#{callback ? "callback=#{callback}&" : ''}key=&sensor=false"
    }
    gmaps_utility_options = {
      src: '//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js'
    }
    capture do
      concat content_tag(:script, nil, gmaps_v3_options)
      concat content_tag(:script, nil, gmaps_utility_options)
    end
end

什么 ?涡轮链接?有吃的吗?

我正在使用 Turbolinks 5,正如您在这段代码中看到的那样,您甚至不需要

$(document).on('ready turbolinks:load')

于 2016-05-03T00:56:43.483 回答