Rails 6 + Webpack、数据表、jQuery

Posted

技术标签:

【中文标题】Rails 6 + Webpack、数据表、jQuery【英文标题】:Rails 6 + Webpack, Datatables, jQuery 【发布时间】:2020-01-17 17:14:52 【问题描述】:

我有一个使用此代码的“全选”按钮:

<script type='text/javascript'>
  $('#check_all').on("click", function() 
    $('input[type="checkbox"]').click();
  );
</script>

自从我升级到 Rails 6 + Webpacker 后,它就停止工作了。 控制台显示此错误:

Uncaught ReferenceError: $ is not defined

我设法通过将environment.js 更改为:

environment.plugins.append('Provide',
  new webpack.ProvidePlugin(
    $: 'jquery',
    jQuery: 'jquery',
    Popper: ['popper.js', 'default']
  )
)

收件人:

environment.plugins.append('Provide',
  new webpack.ProvidePlugin(
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery',
    Popper: ['popper.js', 'default']
  )
)

但一旦修复,数据表就会中断。

任何想法如何让他们一起工作? 谢谢!

【问题讨论】:

您的environment.js 是正确的。哪个源代码行导致ReferenceError? “全选”按钮的代码在哪里以及它是如何进入 application.js 包的? 有关此数据表错误的更多信息? @MaayanNaveh 您是否将app/views/layouts/application.html.erb 中的javascript_include_tag 更改为javascript_pack_tag?我重复你的代码,我没有看到任何错误,并且复选框按预期打勾。 inopinatus.org/2019/09/14/webpacker-jquery-and-jquery-plugins @inopinatus 优秀的系统阅读! 【参考方案1】:

将您自己的 Javascript 移动到包文件中对于可维护性来说是一个不错的选择。但是,我猜这些是动态生成的复选框。绑定运行时它们可能不存在。您可以通过绑定到父元素并使用event delegation 来解决问题。 document.body 是使用 Turbolinks 委托事件的常见绑定选择。

我不喜欢在复选框上调用 click()。结果对用户来说并不总是一致的,它会在浏览器中触发一堆不必要的事件。反转 checked 属性更简洁、更一致。

将 DataTables 作为模块加载需要导入 shim。它是一个较旧的包,它更喜欢 AMD 而不是 CommonJS,并且在 Webpack 环境中会自己绊倒。幸运的是,有一个针对旧代码的标准修复程序,使用 imports-loader。不幸的是,即使这样,它也有一个稍微奇怪的工厂导出,您应该将windowjQuery 变量注入其中。幸好也是documented here。

综上所述,这是一个建议的application.js

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")

import $ from 'jquery'

// Add DataTables jQuery plugin
require('imports-loader?define=>false!datatables.net')(window, $)
require('imports-loader?define=>false!datatables.net-select')(window, $)

// Load datatables styles
import 'datatables.net-dt/css/jquery.dataTables.css'
import 'datatables.net-select-dt/css/select.dataTables.css'

$(document).on('turbolinks:load', () => 
  $(document.body).on('click', '#check_all', () => 
    var checkBoxes = $('input[type="checkbox"]')
    checkBoxes.prop("checked", !checkBoxes.prop("checked"))
  )

  // placeholder example for datatable with checkboxes
  $('#example').DataTable(
    columnDefs: [
      render: (data,type,row) => `<input type="checkbox" value="$row[0]">`,
      orderable: false,
      targets: 0
    ],
    order: [[ 1, 'asc' ]]
  )
)

你需要yarn add imports-loader,因为它是一个 Webpack 选项。

ProvidePlugin 不需要任何这些。除非您依赖它来向第三方代码注入导入,否则可以安全地删除它。

【讨论】:

哇,非常感谢您写得很好的回复!我真的很感谢你花时间 :) 我试了一下,但没能成功。我已经解决了所有问题,它似乎可以编译,但是没有分页/搜索(意思是,dt 不会加载)。控制台显示 1 个错误,但没有指示哪个代码行是违规者。错误:Uncaught ReferenceError: $ is not defined。这是我的application,js:gist.github.com/maayannaveh/51de9d29d89181b104ae2076d17a08e1(我已经注释掉了样式,因为我还不确定如何使它工作) 好的,设法让样式生效。一样。一个错误,没有违规行,dt 不加载 :( 您有未公开的脚本元素或事件属性,它们试图使用 $ 全局变量,但由于不存在而失败。将所有此类代码移动到包中。我看不到您添加了任何代码来实际调用 DataTables - “占位符示例”部分就是这样,将其调整为您自己的应用程序。 您还重复导入了 jquery。删除require('jquery')。可能没有害处,但肯定是多余的和令人困惑的。 经过 3 天的谷歌搜索后,这个答案终于让我的自定义 jquery 代码在 Rails 6 中工作。祝福你。【参考方案2】:

运行yarn add imports-loader

如果您使用 bootstrap3 或其他 CSS 框架,我使用 bootstrap4 数据表,请按照此链接安装: https://datatables.net/download/

在我的config/webpack/loaders/datatable.js

module.exports = 
  test: /datatables\.net.*/,
  use: [
    loader: 'imports-loader?define=>false'
  ]

在我的config/webpack/environment.js

const  environment  = require('@rails/webpacker')
const webpack = require('webpack')
const coffee =  require('./loaders/coffee')
const datatable =  require('./loaders/datatable')

environment.plugins.append('Provide', new webpack.ProvidePlugin(
  $: 'jquery',
  jQuery: 'jquery',
  jquery: 'jquery',
  'window.jQuery': 'jquery',
  Popper: ['popper.js', 'default']
))

/**
 * To use jQuery in views
 */
environment.loaders.append('expose', 
  test: require.resolve('jquery'),
  use: [
    loader: 'expose-loader',
    options: '$'
  ]
)

environment.loaders.prepend('coffee', coffee)
environment.loaders.prepend('coffee', datatable)

module.exports = environment

在我的app/javascript/packs/dashboard.js

require( 'jszip' );

require("datatables.net-bs4")(window, $);
require("datatables.net-responsive-bs4")(window, $);
require("datatables.net-buttons-bs4")(window, $);
require("datatables.net-select-bs4")(window, $);

require("datatables.net-bs4/css/dataTables.bootstrap4.css");
require("datatables.net-responsive-bs4/css/responsive.bootstrap4.css");
require("datatables.net-buttons-bs4/css/buttons.bootstrap4.min.css");
require("datatables.net-select-bs4/css/select.bootstrap4.css");

请随意给用户 import './datatable'.js 中的任何app/javascript/packs 文件中,您喜欢

【讨论】:

【参考方案3】:

以上都不适合我。终于按照本指南让它工作了:https://inopinatus.org/2019/09/14/webpacker-jquery-and-jquery-plugins/。

yarn add datatables.net-bs4 imports-loader

应用程序.js

require('@rails/ujs').start()
require('@rails/activestorage').start()
require('channels')
require('jquery')
require('bootstrap/dist/js/bootstrap')
window.$ = $

require('imports-loader?define=>false!datatables.net')(window, $)
require('imports-loader?define=>false!datatables.net-bs4')(window, $)

【讨论】:

这解决了我的问题(当我使用 jQuery 版本 3.4.1 时甚至不存在,但仅在我将 jQuery 升级到 v3.5.0 时才出现)。这是迄今为止提供的答案中最简单和最干净的。 自从我编写了该指南,上面评价最高的答案,我将添加我的想法:) 你已经正确地应用了相同的原则,但是对于不同的版本和/或一组导入。我怀疑发生的事情是一些外部部件改变了它们的行为或包装。 window.$ = $ 为我排序

以上是关于Rails 6 + Webpack、数据表、jQuery的主要内容,如果未能解决你的问题,请参考以下文章

Rails 6.1.0 [webpack-cli] TypeError:无法读取未定义的属性“插件”

Rails 6 + Webpack + jQuery 刷新时不保存更改

带有 Webpack 和 Yarn 的 Rails 6 上的 ActionController 路由错误

让 Ruby-on-Rails 6/Webpack + Bootstrap 一起正常工作的问题

使用 Webpack 在 Rails 6 上设置 Bootstrap 4.3

$(...).tooltip 不是一个函数 rails 6 webpack