您如何在 Rails 3.1 中使用 Sprockets 编写干燥的模块化咖啡脚本?
Posted
技术标签:
【中文标题】您如何在 Rails 3.1 中使用 Sprockets 编写干燥的模块化咖啡脚本?【英文标题】:How do you write DRY, modular coffeescript with Sprockets in Rails 3.1? 【发布时间】:2011-10-12 13:23:09 【问题描述】:我正处于尝试编写一些合理的 javascript 的早期阶段。我想基本上以我的应用程序名称命名所有内容,以尽可能避免全局变量,但仍然给我一种访问在该位置周围声明的函数的方法。但是,我不想在函数定义中过于冗长。
我理想的 CoffeeScript 应该是这样的:
class @MyApp
@myClassMethod = ->
console.log 'This is MyApp.myClassMethod()'
class @Module1
@moduleMethod = ->
console.log 'This is MyApp.Module1.moduleMethod()'
你明白了。这样我就避免了每次想要正确定义命名空间函数时都必须编写 MyApp.Module.submoduleMethod = ->
- 使用 @
并在我的类定义中定义事物 使事情变得简洁明了。
这一切都很顺利,直到我想将我的功能拆分为多个 CoffeeScript 文件。那么我真正想要的是这样的:
// application.js
class @MyApp
//= require 'module1'
//= require 'module2'
// module1.js
class @Module1
@moduleMethod = ->
console.log 'This is STILL MyApp.Module1.moduleMethod()'
Sprockets 似乎无法做到这一点。
有没有一种明智的方法来要求我的 CoffeeScript 文件在我的容器文件中的正确位置?或者使用 CoffeeScript、Sprockets 和 Rails 3.1 编写模块化代码的另一种方法?
【问题讨论】:
我认为这个问题需要进一步调查——下面的答案还不够好,尤其是。由于coffeescript 的创建者已经删除了“简单模块”页面b/c,因此技术很差。 【参考方案1】:只需保持 module1.js 原样,让 application.js 看起来像这样:
//= require 'module1'
class @MyApp
...
@Module1 = Module1
这将起作用,因为您已将 Module1
设为全局(声明 class @Module1
等同于编写 @Module1 = class Module1
,并且在该上下文中 @
指向 window
),并且在 class @MyApp
正文中, @
指向类本身。
如果您希望Module1
在附加后仅成为全局MyApp
类的属性,则可以添加该行
delete window.Module1
【讨论】:
好主意!如果我的模块名称与页面上其他脚本中的名称冲突,仍然会有问题,对吧?我很挑剔,因为我正在编写可能会使用书签注入其他页面的代码。 啊,在那种情况下,我只需定义一个全局变量,然后将其他所有内容附加到它上面。为此,请翻转您的依赖顺序:在 application.js 中,需要module1.js
,在 module1.js
中,需要 myapp.js
,以便首先定义全局 MyApp
。然后你可以写class MyApp.Module
...
我上面的回答处理了名称冲突问题。使用类很好,但它不像在 ruby 中可以猴子补丁。它将清除任何先前定义的类。 ***.com/questions/6815957/… 解决了这个问题【参考方案2】:
我有一个在我的代码中使用的模块解决方案。
我像下面这样定义我的模块
@module "foo", ->
@module "bar", ->
class @Amazing
toString: "ain't it"
Amazing 可作为
foo.bar.Amazing
@module 助手的实现是
window.module = (name, fn)->
if not @[name]?
this[name] =
if not @[name].module?
@[name].module = window.module
fn.apply(this[name], [])
这里的咖啡脚本网站上写着。
https://github.com/jashkenas/coffee-script/wiki/Easy-modules-with-coffeescript
【讨论】:
感谢您的链接。知道如何扩展它以使其在多个文件中正常工作吗? 它确实适用于多个文件。这就是它的全部意义所在。你说的好是什么意思? 我的意思是不必在每个文件中定义所有父模块。不过,这可能没有我最初想象的那么烦人。 你把@module "foo", -> 代码放在哪里了?你能把它放在application.js中吗?我认为它需要一个 .coffee 扩展名... @bradgonesurfing:coffeescript 的创建者删除了链接 - 他显然认为它不太好......那么有没有合适的方法来组织 JS 文件?例如,我无法使用以前在断开的链接处给出的方法来定义要在整个“类”中使用的常量或“实例变量”......【参考方案3】:这是我用来管理带有 sprockets 的咖啡脚本的模块化模式(也适用于 Rails 4):
# utils.js.coffee
class Utils
constructor: ->
foo: ->
alert('bar!!!')
# private methods should be prefixed with an underscore
_privateFoo: ->
alert('private methods should not be exposed')
instance = new Utils()
# only expose the methods you need to.
# because this is outside of the class,
# you can use coffee's sugar to define on window
@utils = foo: instance.foo
# otherscript.js.coffee
//= require utils
class OtherScript
constructor: ->
@utils.foo() # alerts bar!!!
@utils._privateFoo() # undefined method error
这种方法的一个缺点是您将对象暴露在窗口上。根据您的需要,添加模块加载器或在模块周围采用一些新的 es 语法可能是一个不错的选择。
【讨论】:
以上是关于您如何在 Rails 3.1 中使用 Sprockets 编写干燥的模块化咖啡脚本?的主要内容,如果未能解决你的问题,请参考以下文章
导轨 3.1。如何防止 Rails 使用 CoffeeScript?
Rails 3.1 http 流式传输——js 在头部还是底部?
如何在rails 3.1中使用jquery-addresspicker jquery
如何在 Rails 3.1 中为 CoffeeScript 使用选项“--bare”?