Coffee script & Javascript 结构与组织

Title: Coffee script & Javascript organize
Tags: coffeescript,javascript
Slug: coffeescript
Excerpt: rails coffee script
Date: 2012-09-25

CofeeScript & JavaScript Organize

我需要解决以下问题,相信其它朋友也会碰到,这是我翻查的结果,结论已经在我的项目用了,感觉不错,分享一下。原博文在 http://scriptogr.am/mafai/post/coffeescript

Target

  • 所有js compile在一个js,不论是否需要
  • 不同页面需要运行的js才运行,不需要的不运行

Solution 1

init不同namespace的js

application.html.erb 这段不能用coffee script,原因是动态call init的方法
可以再细分按action name或用正则表达式

:javascript
  $(function() {
    #{"Window.#{params[:controller]}"}.init();
  });

转换成的代码,当在访问 /apples

Window.apples.init()

对应的 apples.js.coffeelike只是为了demo,可以用ujs代替

Window.apples =
  like: (id) ->
        console.log("like apple:" + id)
        return
  init: () ->
        console.log("init apple")
        $(".apple").click () ->
          console.log("click me")
          console.log( $(this).attr("id") )
          Window.apples.like($(this).attr("id"))
          return
        return

oranges.js.coffee

 oranges =
  init: () ->
        console.log("init orange")
        return
  eat: (id) ->
        console.log("eat orange:" + id)
        return

当访问 /apples 时,只会init apples的js,如果是/oranges,则只会init orange js

Solution 2

方案1的变形,不过组织起来更舒服一占o,与方法1差不多

common.js.coffee 将 apples, oranges 等作为namespace

Window.FruitsSite =
  common:
    init: () ->
      console.log("init common")
  apples:
    init: ()->
      console.log("init apples")
    like: (id) ->
      console.log("like apple id: " + id)
  oranges:
    init: () ->
      console.log("init oranges")
    eat: (id) ->
      console.log("eat orange id: " + id)

application.haml 动态按controller名去调用

Window.FruitsSite["#{params[:controller]}"].init();

Solution 3

方案2的变形,将需要用到的 js 类放到 body中,同时细分到不同action页面级别

<body data-controller="apples" data-action="index"">
找出对应 apples 的 index 页面需要init的东西init一下

<body data-js="apples autoscroll"> Iint apples 和 autoscroll

查找一下data-js,然后找出对应的模块init一下就好

例子

apples.js.coffee

Window.FruitsSite =
  apples:
    index:
      init: () ->
        console.log("init apples index page")
        return

applicatoin.haml 其实就是多一个层级而已,另外就是可以将这下面这段代码转成coffee script,不用像上面两个例子写一些恶心js在页面上

 var $body = $("body");
 var controller = $body.attr("data-controller");
 var action = $body.attr("data-action");
 Window.FruitsSite[controller][action].init();

Solution 4

重写 jquery ready方法,利用body class 调用对应的ready

重写jquery ready方法,看不明proxy的那个方法,不过没关系
这段代码来自于 https://github.com/Verba/jquery-readyselector/blob/master/jquery.readyselector.js

(function ($) {
   console.log("try to reset the ready function");
   var ready = $.fn.ready;
   $.fn.ready = function (fn) {
     console.log(this);
     console.log("Context:" + this.context);
     console.log(this.context);
     if (this.context === undefined) {
       console.log("no context defined");
       // The $().ready(fn) case.
       ready(fn);
     } else if (this.selector) {
       console.log("Selector:" + this.selector);
       ready($.proxy(function(){
         $(this.selector, this.context).each(fn);
       }, this));
     } else {
       console.log("Context have but no selector");
       ready($.proxy(function(){
         $(this).each(fn);
       }, this));
     }
   }
 })(jQuery);

写不同的ready函数

$('.apples.index').ready(function () {
   console.log("apple index page init");
 });
$('.oranges.index').ready(function(){
   console.log("oranges index page init");
 });

ready这个方法就可有可无了

$(function() {
});

body中的class一定要以空间分隔

%body{:class => "#{params[:controller]} #{params[:action]}"}

其它的方法还有

用条件语句去控制,只是不那么高明

$(body).hasClass("autoscroll")

只当需要时才new instance

Window.FruitsSite.apples = new Apples;

只能先实例化

创建实例

class Apples
  index:
    init: () ->
      console.log("init apples index page")
      return
console.log(window.FruitsSite)
window.FruitsSite.apples = new Apples

简版

window.FruitsSite.apples =
  index:
    init: () ->
      console.log("init apples index page")
      return
console.log(window.FruitsSite)

CoffeeScript 整合 vim

到 node.js 下载一下pkg(Mac)
装完后

sudo npm install -g coffee-script

mkdir -p ~/.vim/autoload ~/.vim/bundle
curl 'www.vim.org/scripts/download_script.