没有整页刷新,GMaps4Rails和Turbolinks无法加载

我正在使用gmaps4rails在“客户”节目页面上加载地图。 我已经整合了turbolinks以使应用程序更加一致,但是现在我遇到了一个问题,我必须刷新页面以显示地图的地图。 我得到的只是一个空白的地图框架。 刷新页面时,地图会正确显示。

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

在视图中:

 {: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 . 

这里的地图为空白的页面源的要点。

修复程序最终我需要一个完整的页面加载脚本来刷新。

添加

 'data-no-turbolink' => true 

到地图页面的链接工作。

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

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

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

技术背景

数据没有的TurboLink

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

但有几种方法可以使用带有gmaps4rails的turbolinks而不会抑制turbolinks。

Turbolinks回调

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

通常,可以使用$(document).on('page:load', function ... ) ,例如,在Railscast#390中显示 。

JavaScript的同源策略

gmap4rails gem包含的google api脚本从google静态服务器请求另一个脚本。 但是如果动态链接动态包含api,则单一来源策略会阻止对谷歌静态服务器的请求。

单一来源政策本身是一件有用的事情。 虽然有几种方法可以绕过它,但这似乎并不是一件很自然的事情。 相反,执行此操作的“正确方法”是“certificate”网页确实要执行远程脚本(google api),并且恶意脚本不会请求远程脚本。 这是通过在html树中包含直接请求google api的脚本标记来完成的。

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

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

我已经提出了拉取请求 ,希望增加Turbolinks对gmaps4rails的支持。

演示

如果您愿意,请先查看此演示,其中显示了使用带有turbolinks的gmaps4rails:

如何在您的项目中使用它

您可以尝试这一点,并通过将分支添加到您的Gemfile来检查它是否适用于您的项目:

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

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

    ... <%= stylesheet_link_tag "application", :media => "all" %> <%= javascript_include_tag "application" %> <%= gmaps4rails_api_script_tags # <-- THIS IS NEW ----------------- %> <%= csrf_meta_tags %>   ... <%= yield %> <%= yield :scripts %>   

如果出于某种原因,你不想使用这个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请求修复到您的语言环境,如果您的应用程序在国际上使用,这可能不是一件好事。

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

map.js.coffee

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

application.js.coffee

 //= require jquery //= require jquery.turbolinks 

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

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

   

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

application.html.erb

 ....  ... <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> <%= csrf_meta_tags %> # insert the following two lines    ... 

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

的application.js

添加这个:

 //= require gmaps/google 

现在,应该加载地图而无需刷新页面。

我有同样的问题,但我不想关闭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 ); }); }; 

由于我也使用谷歌地方图书馆我有几个function,我可以使用init_google_api()调用

在我想要地图的每个视图中,我只是放了一个

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

在观点的最后。 修复所有内容+保持代码干燥,因为需要多个地图等。

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

您可以直接从Google地图url使用回调

  

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

以下是我的进展方式。 我有一个助手,生成Gmaps脚本标记,并回调正确的函数(+加载其他gmaps脚本)

 # view/your_view.html.erb  <%= 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? 吃的东西?

我正在使用Turbolinks 5,你可以看到这个代码甚至不需要

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