2012-06-04 28 views
5

我試圖在clojurescript包裝knockout.js,但它變得非常困難。我遇到的問題是對「this」變量的引用。我正在考慮放棄,直接使用JavaScript。使用clojurescript包裝knockout.js

我已經採取了關閉的例子和http://knockoutjs.com/examples/helloWorld.htmlhttp://knockoutjs.com/examples/contactsEditor.html

我已經成功地包裹易功能與一些宏。例如:

var ViewModel = function() { 
    this.firstName = ko.observable("Bert"); 
    this.lastName = ko.observable("Bertington"); 

    this.fullName = ko.computed(function() { 
     // Knockout tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName. 
     return this.firstName() + " " + this.lastName(); 
    }, this); 
}; 

變爲:

(defviewmodel data 
    (observing :first_name "Bert") 
    (observing :last_name "Bertington") 
    (computing :name [:first_name :last_name] 
    (str :first_name " " :last_name))) 

然而,更難的事,如:

var BetterListModel = function() { 
    this.itemToAdd = ko.observable(""); 
    this.allItems = ko.observableArray(["Fries", "Eggs Benedict", "Ham", "Cheese"]); // Initial items 
    this.selectedItems = ko.observableArray(["Ham"]);        // Initial selection 

    this.addItem = function() { 
     if ((this.itemToAdd() != "") && (this.allItems.indexOf(this.itemToAdd()) < 0)) // Prevent blanks and duplicates 
      this.allItems.push(this.itemToAdd()); 
     this.itemToAdd(""); // Clear the text box 
    }; 

    this.removeSelected = function() { 
     this.allItems.removeAll(this.selectedItems()); 
     this.selectedItems([]); // Clear selection 
    }; 

    this.sortItems = function() { 
     this.allItems.sort(); 
    }; 
}; 

ko.applyBindings(new BetterListModel()); 

我不知道我能在clojurescript像這場比賽代碼做到: this.allItems.push(this.itemToAdd())

有什麼想法?

+0

如果你能把握住了一個月,我們將開源的Knockout.js啓發,我們一直在使用,在內部實驗室克明計算,觀測庫。請留意我的Github(@lynaghk)。 –

+0

謝謝凱文!我非常期待和圖書館一起玩耍。不過,也有太多的偉大的JavaScript庫,在那裏,有相似類型的宣佈訪問的Clojure沒有其他內部變量的變量的問題。我覺得在js和cljs之間插入一個明確的方法是很重要的。我越用clojurescript安德的JavaScript玩,我越發現不錯的js庫都處於lispy辦法......我只看到了Clojure的學習後的連接。不管怎麼說,希望能得到我的回答您的評論下面 – zcaudate

+0

對http://fluentsoftware.github.com/cljs-binding/一看,不那麼成熟的淘汰賽,但.. – edtsech

回答

5

經過大量的試驗和錯誤,我想通了,如何有clojurescript相同的結構爲JavaScript。

this-as宏有幾個特質,只有當該方法被放入類

例如我想創造的東西,看起來像這樣在JavaScript的工作:

var anobj = {a: 9, 
      get_a: function(){return this.a;}}; 

我要做了很多更多編碼,以獲得clojurescript相同的對象:

(def anobj (js-obj)) 
(def get_a (fn [] (this-as me (.-a me)))) 
(aset anobj "a" 9) 
(aset anobj "get_a" get_a) 

這是一個語言嚴重醜美如cloj URE。事情會變得更糟糕,當你得到相互鏈接的功能時,比如在淘汰賽中發生的事情。

我發現創建一個有很多this的js對象的最好方法是定義一個__init__方法,將它添加到類中,然後運行它,然後將它從類中移除。例如,如果我想再拍對象:

var avobj = {a: this, 
      b: 98, 
      c: this.a 
      get_a: function(){return str(this.a) + str(this.c);}}; 

寫成clojurescript與和__init__方法是這樣的:

(def avobj (js-obj)) 
(def av__init__ 
    #(this-as this 
     (aset this "a" this) 
     (aset this "b" 9) 
     (aset this "c" (.-a this)) 
     (aset this "get_a" (fn [] (str (.-a this) (.-c this)))))) 
(aset avobj "__init__" av__init__) 
(. avobj __init__) 
(js-delete stuff "__init__") 

目前仍然不是JavaScript一大堆更多的代碼...但是最重要的是你獲得與javascript相同的對象。使用這種形式設置所有變量還允許使用宏來簡化。所以現在我已經定義了一個宏:

(defmacro defvar [name & body] 
    (list 'do 
    (list 'def name 
     (list 'map->js 
     { 
      :__init__ 
      (list 'fn [] 
       (list 'this-as 'this 
       (list 'aset 'this "a" "blah")))   
     })) 
    ;(. js/console log ~name) 
    (list '. name '__init__) 
    (list 'js-delete name "__init__"))) 

並且帶有來自jayq的map-> js。utils的:

(defn map->js [m] 
    (let [out (js-obj)] 
    (doseq [[k v] m] 
     (aset out (name k) v)) 
    out)) 

現在我可以寫這樣的代碼:

(defvar avobj 
    a this 
    b 9 
    c (.-a this) 
    get_a (fn [] (str (.-a this) (.-c this)))) 

和答案淘汰賽:

(defvar name_model 
    first_name (observable "My") 
    last_name (observable "Name") 
    name (computed (fn [] (str (. this first_name) " " (. this last_name))))) 

(. js/ko (applyBindings name_model)); 

這是非常好的,我爲它匹配的JavaScript真的很好它的完全可讀!