【问题标题】:UJS Code Organization and InitializationUJS 代码组织和初始化
【发布时间】:2012-02-16 01:55:12
【问题描述】:

我的两部分问题看起来非常基本,但我没有在 UJS 或 jQuery 的介绍、指南或概述中看到任何讨论。我已经阅读了无数其他主题/问题,试图找到可以复制风格或感觉的示例,但玩具示例会询问“我如何在 jQuery 中做 X?”等等,从不真正解释或演示他们的解决方案如何适应更大的应用程序。

这样,我的问题是结构性的还是建筑性的。

'tl;dr' 版本的问题基本上是问“人们如何实际上在大型应用程序中组织和初始化 Unobtrusive JavaScript 代码?”具体来说:

  1. “以不显眼的风格编写 JavaScript 时,如何跨文件组织代码?甚至应该这样做吗?” (我知道只向客户端发送一个文件是有好处的,然后将其缓存起来,所有后续加载都更快)。

  2. "如果相关的 JS 不再显式加载页面,如何确保正确的代码在正确的页面上正确初始化/调用/使用,并且时间不会浪费在运行选择器上与当前页面无关?”

加长版:

在我们的 Rails 应用程序中手动滚动我自己的脆弱的、现在足够好的 JavaScript 几个月后,我终于转换为 UJS 和 jQuery 的方式。我现在已经阅读了所有http://jqfundamentals.com,除了“高级主题”部分。我很容易掌握 jQuery,而且我的页面正在做我想做的事,孤立地

至于“不显眼的 JavaScript”,我不太清楚,但这个想法似乎主要是将 JS 完全分离为外部文件,并在事后通过 某种方式 将 JS 功能绑定到页面中文档准备好后,您将打开并附加功能。如果这不准确或不完整,请纠正我。

但我不明白如何组织我的代码并确保包含正确的 JavaScript 并将其附加到正确的页面。我能想象到的所有方法要么效率极低、笨拙,要么使 UJS 的某些原则无效。

目前的情况是,我有一个庞大而笨拙的 application.js 文件,其中塞满了各种选择器,它们等待将功能放置到我 90% 的页面上不存在的页面元素上。也就是说,第 1 页有 A、B 和 C 项,而第 2 页有 A、D 和 E 项。这经常导致事情中断。我觉得我有两个令人不快的选择:

    1234563只有 document.ready 调用它知道应该在该页面上的元素。我可以实现这一点的明显方法感觉非常难看,例如在页面中放置一个全局 JS 变量并检查它,这打破了最初吸引我的整个 UJS 禅宗。
  1. 将我的 JavaScript 拆分为不同的文件并有选择地加载它们。也就是说,“我在 view01.html.erb 中,因此我需要包含 view01.js”,它只处理 view01.html.erb 上的元素。起初这似乎更好,但在涉及到局部、混合和匹配 .js 文件以及试图保持 DRY 时会变得笨拙。

我选择了 UJS 的这条路,因为它有这种非常干净、禅宗般的吸引力,但应用于更大的项目时,似乎麻烦多于其价值。然而,比我聪明得多的人却坚持不这样做,我完全同意内联和脚本标签绑定的 JavaScript 笨​​拙且丑陋,这让我相信我做错了什么。

到目前为止我做了什么 (又名更长的版本,可能不值得你花时间阅读):

第 1 阶段:我正在开发一个 Rails 应用程序,因此我首先采用了许多 RailsCasts 教程中介绍的路线,这些教程演示了 application.js 中的代码,该代码通过选择器并为其附加一些功能。一切都很好,我有 2 或 3 个页面来做所有漂亮的 jQuery、Web2.0-ish、AJAX-y 的东西,这些天在孩子们中很受欢迎。太棒了!

第 2 阶段: 然后我又制作了一页,事情开始出现问题。我在 application.js 中的所有代码都通过 $('selector') 访问了东西。这个新页面没有任何与其他页面相同的元素,因此当我的其他页面中的代码尝试获取 id='special_area' 的元素时,调用 $('#special_area')[0 ] 中断,因为它是空的。对每个选择器的结果进行空检查感觉是错误的,所以我最终陷入了不使用我所知道和喜爱的 DOM 元素的解决方案,而是使用这些可以链接的花哨的 jQuery 对象。整洁。

第 3 阶段: 我意识到,使用这些链式 jQuery 对象,只要我所有的 ID 都是唯一的,或者我在每个页面上放置某种唯一的 DIV,任何不存在的元素在页面上将返回一个空集并且(希望)不会中断。我还不能肯定地说,无论我想对它们做什么,它们都不会破裂,因为它们是空的,因此我不会假设是这种情况。但不知何故,我可以通过暴力破解整个应用程序中的所有元素并以某种方式智能地忽略当前页面上不存在的元素,从而看到它勉强解决。

此外,jQuery Fundamentals 指南反复讨论了保持运行选择器的成本。如果我只是蛮力运行我所有的选择器并且让它不应用那些不存在的选择器,我会在每个页面上放置一个巨大的静态开销,因为随着我的应用程序大小的增长,单.js 文件,每个页面都要检查越来越多的实际上并没有出现在上面的元素!

第 4 阶段:我了解了命名空间是如何在 JS 中完成的,虽然我打算使用它们,但我不认为它可以解决这个特定问题。如果可以,请解释。除此之外,我表达失望和困惑的能力已经崩溃,我想知道人们如何实际上在 Real Life™ 中组织和初始化 UJS 代码?

【问题讨论】:

  • 不是在每个页面加载时检查现有元素并有条件地为当前页面执行合适的代码(如您所说,这可能会导致性能不佳),您可以反过来尝试。即:在每个特殊的布局/页面中包含一个小的内联 javascript(最小化请求数量),它在您的 appliaction.js 中调用正确的初始化程序。该解决方案可能不严格遵循 UJS 范式,但它可能足够实用/有益,足以证明其使用的合理性。
  • 我意识到这并不能回答您上面的所有问题,但这是一个很好的起点,可以很好地控制给定控制器和操作将运行/附加/任何 JS 的好方法:@ 987654322@

标签: jquery ruby-on-rails architecture unobtrusive-javascript


【解决方案1】:

tl;博士回答

  1. 将您的代码拆分为 AMD 模块,然后使用 AMD 加载程序(如 RequireJS)加载它们。是的,它应该完成。
  2. 在您的局部视图中,只需 require() 并执行相应的模块

更长的答案

使用诸如RequireJS 之类的 AMD 加载程序,您可以将代码分离到单独的模块中。您还可以将共享代码(例如 jQuery)存储在公共模块中,然后将其用作视图模块的先决条件。

您可以阅读 Asynchronous Module DefinitionRequireJSusing it with jQuery,但这是我的处理方式:

  1. 您的 AMD 加载程序有主文档 includeconfigure。您可能需要加载共享模块(jQuery 等),以便浏览器可以在请求之间缓存它们。
  2. 对于每个局部视图,implement a coresponding JS module
  3. 在您的局部视图中,添加一个脚本块来加载模块并执行其初始化函数

查看模块

您的模块将如下所示(我们也使用 jQuery 作为 AMD 模块):

js/partials/view01.js

define(["jquery", function($) {
  "use strict";
  return {
    init: function() {
      // This is where you do your UJS work for this partial
      // ...
    }
  }
});

局部视图

在您的局部视图中,您将加载模块并调用 init 函数:

view01.html.erb

<script>
require("partials/view01", function(view) {
  view.init();
});
</script>
<!-- More HTML for this partial view -->

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-14
    • 2011-12-19
    • 2011-12-07
    • 1970-01-01
    • 2023-03-04
    • 2012-07-05
    • 1970-01-01
    相关资源
    最近更新 更多