【问题标题】:GMaps4Rails and Turbolinks not loading without full page refreshGMaps4Rails 和 Turbolinks 在没有整页刷新的情况下无法加载
【发布时间】:2012-12-10 19:23:23
【问题描述】:

我正在使用 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 .

地图为空白的页面源的要点here

【问题讨论】:

  • 那是因为 google 脚本不是通过 turbolinks 执行的。将它添加到你的布局中。
  • 嘿,感谢您回复我。什么谷歌脚本,我应该把它放在布局的什么位置?
  • 加载整页,看源码。这只是基本的谷歌地图 js
  • 奇怪,我刚刚检查了两个来源,它们是相同的。地图不存在的来源要点在这里:gist.github.com/4254266
  • 将“'data-no-turbolink' => true”添加到将我发送到显示页面的链接中,有效。但理想情况下,地图无论如何都可以工作。

标签: ruby-on-rails google-maps-api-3 gmaps4rails


【解决方案1】:

修复结果是我需要加载整个页面才能刷新脚本。

添加

'data-no-turbolink' => true

指向有效地图页面的链接。

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

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

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

【讨论】:

    【解决方案2】:

    技术背景

    data-no-turbolink

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

    但是有几种方法可以通过 gmaps4rails 使用 turbolinks 不抑制 turbolinks。

    Turbolinks 回调

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

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

    JavaScript 的同源政策

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

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

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

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

    我已拉取request,希望为 gmaps4rails 添加 Turbolinks 支持。

    演示

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

    如何在你的项目中使用它

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

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

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

    <!-- 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. 加载google maps api 本身。
    2. 加载静态文件,由api加载。

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

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

    【讨论】:

    • 如果我将您的代码放在浏览器控制台中,它会显示地图并在以下页面更改后也显示它。如果我将它放在 application.js 文件的末尾,它不会显示地图。
    • 我看到你的前叉改进了 turbolinks。它准备好与 turbolinks 一起使用了吗?
    • @Danil :它应该可以使用了。它在我的项目中运行良好。但可以肯定的是,我目前正在设置一个新的演示应用程序。我会回来找你的,可能今天或明天。如果你试一试,如果你有问题,请告诉我:github.com/fiedl/Google-Maps-for-Rails/issues
    • @Danil :它确实有效。看看这个演示:gmaps-turbolinks-demo.herokuapp.com
    【解决方案3】:

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

    ma​​p.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
    

    【讨论】:

    • 拥有两个听众似乎是正确的答案。这类似于您在执行 turbolink 时执行 $(document).on("ready page:load", function(...)) 的方式。绝对是列表中的最佳答案!
    • 对我有用,最好总是重新加载整个页面。
    • 注意,对于 turbolinks 5,事件被称为 turbolinks:load 而不是 page:load
    【解决方案4】:

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

    注意gmaps4rails gem 有javascript dependencies,即:

    <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 将它们添加到您的所有页面。

    application.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将源代码添加到您的资产管道中

    application.js

    添加这个:

    //= require gmaps/google
    

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

    【讨论】:

    • 请解释我在投票时如何改进这个答案。
    【解决方案5】:

    我遇到了同样的问题,但我不想关闭 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 函数和作为参数传入的函数(这就是我使用函数表达式的原因)。所以每次调用函数时都会运行代码。

    【讨论】:

      【解决方案6】:

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

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

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

      这是我的操作方式。我有一个助手可以生成 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')

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-06
        • 1970-01-01
        • 2020-11-14
        相关资源
        最近更新 更多