我是一名前端开发人员,目前正在一个关于Ruby on Rails项目的团队中工作。这不是SPA。所有页面呈现都在服务器端完成。
Project有几十个像
这样的逻辑视图if true render this partial else render another partial
我尝试遵循DRY原则,我从arkency blog学到了很多东西,并尝试尽可能多地实现可重复使用的组件。
但是我觉得缺少来自React的componentDidMount
之类的东西。
所以我的问题是:在rails部分中编写内联javascript(即添加逻辑)是否可以? 为可维护的Rails应用程序编写Javascript的最佳方法是什么?
答案 0 :(得分:2)
可以在rails部分中编写内联javascript(即添加逻辑)吗?
为可维护的Rails应用程序编写Javascript的最佳方法是什么?
您将获得大量基于意见的答案。这个问题确实没有真正的答案。我的回答是1)以意见为基础,2)没有近乎完美的地方。
话虽如此,我想提出自己的看法。在过去几年里,我已经看到并构建了大型和小型Rails应用程序(10个js文件和100多个应用程序的应用程序),我对这些应用程序中的JavaScript组织以及我见过的应用程序非常不满意穿过GitHub。我已经看到无数的JavaScript文件充满了无组织和无关联的代码。这似乎对我来说不像Rails。在过去的几个月里,我一直在努力寻找解决方案,我发现有一个解决方案可以在Rails应用程序上最接近组织良好的JavaScript代码库。而且我认为一些Rails理想也是如此。这种方法的一个缺点是它在全球范围内徘徊......我很乐意从JS开发人员那里了解如何解决这个问题。
这是Medium post:
https://medium.com/@cblavier/rails-with-no-js-framework-26d2d1646cd#.36zis335e
我对此做了一些调整,因为有时您需要共享代码,例如,为用户提供共享表单的代码。但是,我想赞美@cblavier。所以请花点时间阅读他的帖子,因为它有一个很好的信息吨,我不会在下面详细介绍。
要求:Coffeescript,Turbolinks和jQuery
# app/helpers/application_helper.rb
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的时间!
# initializer.coffee
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 # turbolinks:load is master branch of turbolinks, if you are using older version, it's page:load
$(document).on 'page:before-change', ->
window.applicationView.cleanup()
true
$(document).on 'page:restore', ->
window.applicationView.cleanup()
pageLoad()
true
# app/assets/javascripts/views/application_view.coffee
window.Views ||= {}
class Views.ApplicationView
render: ->
# pretty much global JS code can be initialized here. It's nice
# to keep the render() method clean though. Like this:
@setupElements()
setupElements: ->
$('[data-toggle=tooltip]').tooltip() # just an example
cleanup: ->
现在您已经进行了这些设置,现在是时候开始添加页面JavaScript了。这只是页面的一个示例。 users_controller#show
Views.Users ||= {}
class Views.Users.ShowView extends Views.ApplicationView
constructor: ->
# find and cache DOM objects, etc
# ex:
@someButton = $('[data-behavior=expand-user-info]')
render: ->
super() # this is important. It calls render() on ApplicationView
# example stuff
@bindEventListeners()
bindEventListeners: ->
t = this
@someButton.on 'click', ->
t.expandUserInfo()
expandUserInfo: ->
alert('woohoo!')
cleanup: ->
super()
如果您之前注意到,我们在initializer.coffee
方法中调用了一个方法initializePageBase()
。当我使用结构from that Medium post时,遇到了edit
和new
视图中需要相同javascript的问题。那initializePageBase()
是解决问题的第一步。它将查找BaseView类。这是一个例子:
# app/assets/javascripts/views/users/base_view.coffee
Views.Users ||= {}
class Views.Users.BaseView # you don't need to extend ApplicationView here, because we are already initializing it.
render: ->
# code
答案 1 :(得分:0)
解决问题的一种方法是使用react.rb gem(和reactive_rails_generator进行安装)
这将允许您以您习惯的反应方式编写视图。
尽管它不是单页应用程序react.rb可以简单地作为你的模板语言。如果你有一些互动页面功能,那么你就可以去了。
还有一个反应记录宝石可能值得研究。