没有整页刷新,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文件:
- 加载谷歌地图api本身。
- 加载由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')