Rails内联JavaScript和最佳实践

10

我对使用Rails还不是很熟悉,但我正在开发的一个应用程序进展顺利。然而,我正在查看生成的HTML并注意到一些像...

<script type="text/javascript">
//<![CDATA[
Droppables.add(...);
//]]>
</script>

这些代码散布在HTML中,当然对应着我使用的地方:

<%= drop_receiving_element ... %>
我想知道是否有更好的方法来做到这一点,或者使它更加简洁?其中一些脚本标签来自于局部文件,因此将它们放在页面底部并不会在这种情况下有所帮助。另一个选择可能是将所有这些“标记块”推入数组中,然后在application.rhtml文件中编写它们,但仍然有些混乱...

记录一下,在Rails 3中将不再是这种情况。JavaScript助手方法将是无侵入的(没有脚本标签)并且与库无关(可用于jQuery,Prototype等)。 - ryanb
5个回答

9
如果您真的想使用最佳实践,请不要使用内联JavaScript。保持HTML、CSS和JavaScript的干净和分离。理想情况下,HTML文件应该在没有CSS和JavaScript的情况下可用。
在我看来,最清晰的方法是只使用纯html/css构建您的应用程序,并使用不显眼的JavaScript来提供更好的用户体验。
一种模式是将所有JS文件包含在页面底部,并使用onDomReady等功能开始运行代码。
基于评论,我想添加一些可能的选项来帮助您入门:
  • JQuery
  • YUI
  • Prototype

我意识到这通常是最佳实践,但我想从Rails的角度来看看这个问题。我见过很多Rails应用程序都使用这些脚本生成器,它们似乎只是在被调用的任何地方输出脚本块... - Matthew Savage
很多asp.net开发者制作只能在IE浏览器上使用的网站,但这并不意味着你也应该这样做。我强烈建议不要使用这样的“助手”。 - TomHastjarjanto

4

最佳实践是删除所有内联JavaScript。然而,我遇到过三种情况,你绝对需要使用内联JavaScript:

1. 解决图像错误

如果图像标签引用了不存在的图像路径,防止图像错误出现(即使在Web检查器中也是如此)的唯一方法是执行以下操作:

<img src="/i/dont/exist.png" onerror="$(this).attr("src", "/i/do/exist.png")" />

以下代码不起作用,因为在使用jQuery抓取图像之前,onerror事件已被执行:
$("img").error(function() {
  $(this).attr("src", "/i/do/exist.png")
});

以下代码同样无法工作,因为 onerror 事件不会冒泡:
$("img").live("error", function() {
  $(this).attr("src", "/i/do/exist.png");
});

所以你必须使用内联javascript。

2. 在页面加载时呈现javascript模板

如果你等到$(document).ready将内容的源代码绘制在dom中的某个空容器元素中,用户会在一瞬间看到空白的位置。这就是为什么当你的Twitter页面首次加载时,动态内容为空的原因。即使您只是在dom底部放置一个外部脚本文件,并在其中将动态生成的html元素附加到页面上,甚至不使用$(document).ready,也为时已晚。你必须在容器元素添加后立即附加动态节点:

<script>App.bootstrap({some: "json"});</script>
<nav id='navigation'></nav>
<header id='header'></header>
<section id='content'>
  // dynamic content here
</section>
<script>App.renderContent();</script>
<aside id='sidebar'>
  // dynamically toggle which one is selected with javascript
  <nav>
    <h3>Search By Category</h3>
    <ol>
      <li>
        <a href="/category-a">Category A</a>
      </li>
      <li>
        <a href="/category-b">Category B</a>
      </li>
    </ol>
  </nav>
</aside>
<script>App.renderSidebar();</script>
<footer id='footer'></footer>

3. 使用JSON引导您的应用程序

如果您正在使用JSON + javascript模板,将第一组数据引导到响应主体中是一个好主意,通过在页面中内联包含它(在上面的dom示例中也是如此)。 这样做可以避免需要额外的AJAX请求来呈现内容。

其他所有事情都应该使用无侵入式Javascript完成

Rails有很多javascript助手,值得庆幸的是,在Rails 3中,大部分(全部?)都是无侵入式的。他们现在使用data-属性和外部rails.js文件。 然而,许多半Ruby半JavaScript的宝石仍然编写帮助器方法以内联添加复杂的JavaScript:

这很有帮助,但我认为只要有一个清晰的README文件描述如何将JavaScript添加到您的application.js中就更有用了。外部javascript使得以后定制/扩展功能变得更加容易,并且可以更好地控制系统,并最小化跨html页面的复制(因此响应主体更小,浏览器可以缓存外部javascript文件)。除非您需要处理缺少图像、瞬时呈现或引导某些JSON外,您可以将其他所有内容放在外部JavaScript文件中,而不必使用Rails JavaScript / AJAX助手。


3
有时候内联JavaScript对于关键的、快速的视图(例如某些着陆页)或者小片段(例如Facebook SDK初始化,分析/Kissmetrics初始化脚本等)非常有用,因为不使用外部库可以加快页面加载。对于这些情况,建议在布局中使用一个_partial _facebook.js.erb,并定义一个辅助函数:
module ApplicationHelper
  def facebook_tag
    content_tag :script, render(partial: 'layouts/facebook.js')
  end
end

接下来,创建文件_facebook.js.erb,并使用已定义的帮助程序将内联JavaScript包含在application.html.erb中:

<%= facebook_tag %>

对于其他情况,比如你提到的内联 JavaScript 的部分,我建议像其他答案建议的那样使用不显眼的 JavaScript。


谢谢你!你有什么线索可以将渲染包装在uglify步骤中吗?更多的是学术练习... - TomFuertes
在呈现partial后,您应该包含调用uglifier gem的代码。但是您需要注意计算时间或缓存结果。一般来说,我建议只使用已经压缩过的js,因为这种方法只适用于某些众所周知的片段。 - Jose

1

这个问题困扰了我一段时间,最终我想出了一个双管齐下的方法。

如果你正在为一个封闭域开发Web应用程序,搜索引擎性能和JavaScript不是问题,那么就务实地让Rails的JavaScript助手完成它们的工作。

如果你正在为广泛的Web开发,则按照Tomh的建议编写纯HTML / CSS代码,然后在onDomReady上进行增强。

如果你仍然想使用像button_to_remote这样使用内联JavaScript的Rails助手,则编写页面加载处理程序以向服务器发送Ajax请求。然后,您可以使用page.replace / page.replace_html将常规页面元素替换为从助手返回的代码。


1

我也建议采用不显眼的JavaScript方法,并使用jQuery

如果您想了解如何在Rails中使用此方法的入门教程,请查看Ryan Bates的jQuery + Rails screencast

如果您想继续使用jQuery帮助程序,请查看jRails,但如果这样做,您仍将违反不显眼的JavaScript原则。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接