3

我正在尝试获取Bootstrap Native在 Rails 5 应用程序中与Turbolinks 5一起使用。当我第一次加载页面时,Bootstrap 下拉菜单工作正常,但导航到另一个页面后,Bootstrap 下拉菜单不再工作。就好像 Bootstrap 的事件侦听器断开连接一样。

我已经看到几个关于 Bootstrap 的 jQuery 实现的问题解决了这个问题,但是,我有兴趣使用Bootstrap Native并从我的 JS 堆栈中消除 jQuery 很感兴趣。

以下是一些细节:

应用程序.js

# app/assets/javascript/application.js
//= require turbolinks
//= require rails-ujs
//= require polyfill
//= require bootstrap-native

应用程序布局

# views/layout/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= csrf_meta_tags %>
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  </head>
  <body>
    <%= render 'layouts/header' %>
    <div class="container">
      <%= yield %>
    </div>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload', 'data-turbolinks-eval': 'false' %>
  </body>
</html>

bootstrap-native 这是Bootstrap Native 包

从我的 Javascript 标记中删除'data-turbolinks-eval': 'false',从而在每个 Turbolink 导航上重新评估应用程序的所有 Javascript,确实解决了 Bootstrap Native 问题,但它会导致 rails-ujs 抛出异常。

关于如何解决这个问题的任何想法?

4

4 回答 4

3

BSN 开发人员在这里,想着为什么不将这个自定义代码添加到 BSN 库之外,以便于维护?

var container = document.getElementById('myContainer');
document.addEventListener('turbolinks:load', function(){
  container = container || document.getElementById('myContainer');
  Array.prototype.forEach.call(container.querySelectorAll('[data-spy="affix"]'), function(element){ new Affix(element) });
  Array.prototype.forEach.call(container.querySelectorAll('[data-dismiss="alert"]'), function(element){ new Alert(element) });
  Array.prototype.forEach.call(container.querySelectorAll('[data-toggle="buttons"]'), function(element){ new Button(element) });
  Array.prototype.forEach.call(container.querySelectorAll('[data-ride="carousel"]'), function(element){ new Carousel(element) });
  Array.prototype.forEach.call(container.querySelectorAll('[data-toggle="collapse"]'), function(element){ new Collapse(element) });
  Array.prototype.forEach.call(container.querySelectorAll('[data-toggle="dropdown"]'), function(element){ new Dropdown(element) });
  Array.prototype.forEach.call(container.querySelectorAll('[data-toggle="modal"]'), function(element){ new Modal(element) });
  Array.prototype.forEach.call(container.querySelectorAll('[data-toggle="popover"]'), function(element){ new Popover(element) });
  Array.prototype.forEach.call(container.querySelectorAll('[data-spy="scroll"]'), function(element){ new ScrollSpy(element) });
  Array.prototype.forEach.call(container.querySelectorAll('[data-toggle="tab"]'), function(element){ new Tab(element) });
  Array.prototype.forEach.call(container.querySelectorAll('[data-toggle="tooltip"]'), function(element){ new Tooltip(element) });
},false);

您应该只查看特定的容器 turbolinks 更新,因为您不会更新任何其他内容,并且您需要尽可能快地进行更新。

我还更新了wiki 页面以包含一个通用示例。

更新 从 BSN 版本 2.0.20 开始,您可以在您的站点中使用该库<head>而无需任何额外的脚本,并且您可以turbolinks更轻松地做到这一点:

var container = document.getElementById('myContainer');
document.addEventListener('turbolinks:load', function(){
  container = container || document.getElementById('myContainer');
  BSN.initCallback(container);
}, false);

如果您在BSN控制台中输入 hit Enter,您将获得以下对象:

BSN = {
  version: '2.0.20',
  initCallback: function(lookup){},
  supports: [ /* an array with supported components */ ]
}

请记住,您不必将其myContainer用作 turbolinks 目标的 ID 属性,您可以使用任何东西来使该元素独一无二,我建议使用像data-function="turbolinks-autoload".

下载最新的大师并试一试。

于 2017-10-31T10:55:04.233 回答
1

主要修订

在 Bootstrap Native 开发团队的一名成员接受了答案之后,我修改了我在我的应用程序中实现的解决方案。我的解决方案与公认的解决方案略有不同,因为我的侦听器将在整个 DOM 中搜索 Bootstrap 组件。相比之下,公认的解决方案只会在包含id="myContainer. 接受的解决方案将执行得更快,因为它只搜索 DOM 的一个子集。但是,它需要开发人员将相关的 Bootstrap 组件包装在带有myContainerid 的标签中。

任何一种解决方案都有效。我的解决方案运行速度会慢一些,但会导致编码更容易,并且不太容易出现开发人员引发的错误。以下是详细信息:

应用程序/资产/javascript/application.js

//= require turbolinks
//= require rails-ujs
//= require polyfill
//= require bootstrap-native
//= require bootstrap-native-turbolinks

应用程序/资产/javascript/bootstrap-native-turbolinks.js

document.addEventListener('turbolinks:load', function(){
  Array.prototype.forEach.call(document.querySelectorAll('[data-spy="affix"]'), function(element){ new Affix(element) });
  Array.prototype.forEach.call(document.querySelectorAll('[data-dismiss="alert"]'), function(element){ new Alert(element) });
  Array.prototype.forEach.call(document.querySelectorAll('[data-toggle="buttons"]'), function(element){ new Button(element) });
  Array.prototype.forEach.call(document.querySelectorAll('[data-ride="carousel"]'), function(element){ new Carousel(element) });
  Array.prototype.forEach.call(document.querySelectorAll('[data-toggle="collapse"]'), function(element){ new Collapse(element) });
  Array.prototype.forEach.call(document.querySelectorAll('[data-toggle="dropdown"]'), function(element){ new Dropdown(element) });
  Array.prototype.forEach.call(document.querySelectorAll('[data-toggle="modal"]'), function(element){ new Modal(element) });
  Array.prototype.forEach.call(document.querySelectorAll('[data-toggle="popover"]'), function(element){ new Popover(element) });
  Array.prototype.forEach.call(document.querySelectorAll('[data-spy="scroll"]'), function(element){ new ScrollSpy(element) });
  Array.prototype.forEach.call(document.querySelectorAll('[data-toggle="tab"]'), function(element){ new Tab(element) });
  Array.prototype.forEach.call(document.querySelectorAll('[data-toggle="tooltip"]'), function(element){ new Tooltip(element) });
},false);

供应商/资产/javascripts/

最后,我将我的应用程序 javascript 标记移至<head>并在没有 tuborlinks-eval 和 turbolinks-track 的情况下异步加载它。这将 Javascript 配置为在初始页面加载时运行一次。turbolinks:load每次访问 turbolinks 页面时都会调用该侦听器,并将 Bootstrap Native 事件侦听器附加到 DOM 中的适当组件。

应用程序/视图/布局/application.html.erb

...
<head>
  ...
  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload', 'data-turbolinks-eval': 'false', async: true %>
</head>
...

在撰写本文时,此解决方案位于生产 Rails 5.1 应用程序中。

顺便说一句,在application.js中列出的所有 Javascript ,当连接和缩小时,都小于 20KB。相比之下,jQuery本身缩小了 86KB。 Bootstrap Native可以显着缩短应用程序的下载时间。

于 2017-10-21T18:59:30.667 回答
1

使用 Turbolinks 时,您很可能希望将应用程序 JavaScript 文件放在<head>

# views/layout/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= csrf_meta_tags %>
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>
  <body>
    <%= render 'layouts/header' %>
    <div class="container">
      <%= yield %>
    </div>
  </body>
</html>

尽管这似乎违背了传统的最佳实践,但 Turbolinks 的性能优势在于脚本仅在初始页面加载时加载。

如果引导本机库在 上初始化其插件/函数DOMContentLoaded,您可能还需要在 上手动调用这些函数,然后在必要时turbolinks:load将它们拆除(通常在 上)。turbolinks:before-cache

于 2017-10-21T09:41:19.380 回答
0
var bsn = require('bootstrap.native/dist/bootstrap-native-v4');

document.addEventListener('turbolinks:load', () => {
    BSN.initCallback();
});
于 2019-08-20T11:40:01.170 回答