“在Rails的局部视图中编写内联JavaScript(即添加逻辑)可以吗?”
我的回答是否定的。这样做不易于维护,而且很丑陋。
“那么,在可维护的Rails应用程序中编写JavaScript的最佳方法是什么?”
您将得到许多基于观点的答案。实际上,这个问题没有一个“正确的答案”。我的回答既是基于观点的,也远非完美。
话虽如此,我想提出自己的观点。在过去几年中,我见过并构建了大小不同的Rails应用程序(包括10个js文件和100+的应用程序),我对这些应用程序以及我在GitHub上看到的应用程序中JavaScript的组织方式非常不满意。我看到无数个充斥着无组织和不相关代码的JavaScript文件。这对我来说似乎并不像Rails。在过去的几个月中,我一直在尝试找到解决办法,有一个解决方案最接近在Rails应用程序上实现良好组织的JavaScript代码库,并且我认为它符合一些Rails的理念。这种方法的一个缺点是它会污染全局作用域...我很想听听JS开发者如何解决这个问题。
这是Medium文章链接:
https://medium.com/@cblavier/rails-with-no-js-framework-26d2d1646cd#.36zis335e
我对此进行了一些调整,因为有时您需要共享代码,例如为用户提供支持的共享表单的代码。但是,请允许我将所有功劳归于 @cblavier。因此,请务必花时间阅读他的帖子,因为它包含了大量的优秀信息,我在下面不会进行完整的详细说明。
要求: Coffeescript、Turbolinks 和 jQuery。
def js_class_name
action = case action_name
when 'create' then 'New'
when 'update' then 'Edit'
else action_name
end.camelize
"Views.#{controller_name.camelize}.#{action}View"
end
对于上述助手,如果您的应用程序具有命名空间控制器,则需要考虑命名空间控制器。不过这应该很容易。我认为以下代码可以解决问题。
"Views.#{controller_path.camelize.gsub('::', '.')}.#{action}View"
好的,现在你想将它添加到你布局中的
<body>
标签中。
<body data-class-name="<%= js_class_name %>">
时间到了,该用JavaScript了!
pageLoad = ->
className = $('body').attr('data-class-name')
initializePage(className)
initializePageBase(className)
initializePage = (className) ->
window.applicationView = try
eval("new #{className}()")
catch error
new Views.ApplicationView()
window.applicationView.render()
initializePageBase = (className) ->
modules = className.split('.')
modules.splice(modules.length - 1, 1)
window.baseView = try
eval("new #{modules.join('.')}.BaseView")
window.baseView.render() unless window.baseView is undefined
$(document).on 'turbolinks:load', pageLoad
$(document).on 'page:before-change', ->
window.applicationView.cleanup()
true
$(document).on 'page:restore', ->
window.applicationView.cleanup()
pageLoad()
true
window.Views ||= {}
class Views.ApplicationView
render: ->
@setupElements()
setupElements: ->
$('[data-toggle=tooltip]').tooltip()
cleanup: ->
既然你已经设置好了这些,现在是时候开始添加页面JavaScript了。这里只是一个页面的示例:
users_controller#show
。
Views.Users ||= {}
class Views.Users.ShowView extends Views.ApplicationView
constructor: ->
@someButton = $('[data-behavior=expand-user-info]')
render: ->
super()
@bindEventListeners()
bindEventListeners: ->
t = this
@someButton.on 'click', ->
t.expandUserInfo()
expandUserInfo: ->
alert('woohoo!')
cleanup: ->
super()
如果您之前注意到了,在`initializer.coffee`方法中,我们调用了一个名为`initializePageBase()`的方法。当我使用
Medium帖子中的结构时,我遇到了一个问题,需要在
edit
和
new
视图上都使用相同的JavaScript。`initializePageBase()`是解决这个问题的第一步。它将查找一个名为BaseView的类。以下是一个示例:
Views.Users ||= {}
class Views.Users.BaseView
render: ->