KnockoutJs怎麼樣?

請客觀的說下KnockoutJs的優缺點。


優點:代碼精緻優雅,體積不大,兼容性好

缺點:業務代碼繁瑣,性能一般

說實話,knockout是非常好的一個東西,但同時代的競爭對手過於妖孽,AngularJS力挫群雄,重量級的都用它去了,輕量的又用BackBone去了,再輕量的壓根都不用這些東西,所以……

但Knockout後來也還是一直在發展,也有自己的組件化思路,從其定位來看,Vue跟它是最接近的,就是視圖層的組件化MVVM框架,可惜它現在看來已經沒戲了,屬於被拍死在沙灘上的,慘


優點:MVVM的思想,雙向綁定。ko有種玩街霸的感覺,寫代碼帶感。

缺點:默認的綁定是內置的,如果要改不靈活。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

所以,自己寫了一個雙向綁定的工具:bindtemplate

可以把結構化的數據雙向綁定到容器的子元素中

以下是一個有任意結構的JSON對象。

{
"name":"Jhon",
"parents":["Tom","Jerry"]
}

我想把它雙向綁定到DOM組件上。

&
&
&Name:&
&&&
& &
&Parents:&
&&&
&&&
& &

通常的做法是,用選擇器來確定目標,手動完成賦值和取值操作。

賦值:

$("#component").find("&>div:first-child&>span:last-child").html(json.name);
$("#component").find("&>div:last-child&>span:nth-child(1)").html(json.parents[0]);
$("#component").find("&>div:last-child&>span:nth-child(2)").html(json.parents[1]);

取值:

var name=$("#component").find("&>div:first-child&>span:last-child").html();
var father=$("#component").find("&>div:last-child&>span:nth-child(1)").html();
var mother=$("#component").find("&>div:last-child&>span:nth-child(2)").html();

雖然這些賦值和取值操作,可以封裝到組件中,作為公有方法

但是依然掩蓋不了繁瑣的事實。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

於是,我就借鑒了常用MVVM框架的實現方式,

在目標元素上添加自定義標籤,來實現雙向綁定

&
&
&Name:&
&&&
& &
&Parents:&
&&&
&&&
& &

可以看到,屬性data-model的值是一個字元串,它由DOM元素的值在JSON中的位置決定。

data-model="name",那麼該span的值就是json.name

data-model="parents[0]",那麼該span的值就是json.parents[0]

data-model="parents[1]",那麼該span的值就是json.parents[1]

用法如下:

$("#component").bindTemplate("setData",{
data:json
});

(旁白:這裡也可以不叫json啊,叫my-json也行。。。

取值是對稱的操作。

var result=$("#component").bindTemplate("getData");

得到的這個值就是有結構的JSON了。

{
"name":"Jhon",
"parents":["Tom","Jerry"]
}

好爽!

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

可是,這很不靈活啊。

我為什麼一定要使用data-model屬性?

我為什麼一定要賦值到span的innerHTML中?

你說的對!

這些應該都是可配置的。

我要把JSON的值,綁定到data-my-value屬性上,

並且我使用data-my-model來指定值的位置。

$("#component").bindTemplate("setData",{
data:json,
attr:"data-my-model",
set:function(value){
var $field=this;
$field.attr("data-my-value",value);
}
});

對的,怎麼綁,是一個函數,只要傳給我就行了。

感謝JavaScript的first-class function

於是,輸出結果如下,

&
&
&Name:&
&&
& &
&Parents:&
&&
&&
& &

還要設置如何取值,沒問題,只需要寫一個get方法即可。

var result=$("#component").bindTemplate("setData",{
data:json,
attr:"data-my-model",
get:function(value){
return $field.attr("data-my-value");
}
});

我們的結果依然是結構化的,妥妥的。

{
"name":"Jhon",
"parents":["Tom","Jerry"]
}

好一個面向對象的組件化思維!

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

可是,我不想每次都寫這個set和get方法啊。

當然可以!

寫個配置文件就行了,這裡就不展開了,詳見:bindtemplate

而之前的屬性data-model和賦值到innerHTML只是我後來加的一個配置文件而已。

這樣才能保證工具的核心是最小的,而擴展是豐富的

(其實knockout也是這麼乾的,只不過附加了很多沒用的東西,feature hell。。。


如果你需要在現有項目中給複雜業務增加靈活性,降低開發難度的話,knockout是很好的框架。一旦業務邏輯規模一擴大一複雜,就hold不住了。


ko在我最近2年做的項目里一直作為主力框架用(嘗試過Angular,Backbone,React),為什麼選擇ko,原因如下:

1、PC端兼容IE6;

2、足夠輕量,可以在移動端使用,即很多時候PC端和移動端可以共享代碼;

3、更接近底層(沒有過度封裝,原理簡單),可以擴展的,雖然並不是太優雅,但是基本要的功能都有了;

缺點:

1、因為要兼容IE6,要用observable才能雙向綁定(增加工作量,但是換來性能);

總結:

如果你的項目同時要搞PC和移動端,目前來說沒有比KO更好的方案了。

Angular: 不兼容IE8以下,太重,不適合移動端,並且不能跟別的技術好好相處;

Backbone:適合初學者,有Model類,代碼最終不會有太多坑,但實際它沒幫你做什麼,即無法減少工作量;

React:不兼容IE8以下,對於移動端略重(jsx是極好的),沒有雙向綁定稍微麻煩,React Native大法好,目前最有價值的投資方向,跟NG一樣不能跟別的技術好好相處,無法夾雜一些原生DOM的用法;


樓主,新手來訪,剛用ko3個月,請問你們是如何處理ko.computed監聽變數之後出現太多依賴調用的問題呢?比如說當頁面某一個view發生變化的時候,就會出現多次多處重複調用的情況。


推薦閱讀:

主流的MVVM框架中如何做國際化?
在開發過程中如何應用mvvm思想(非現有的框架)?
隨著各種前端MVVM,MVC框架的流行,jQuery等傳統JS庫是否有走向邊緣的趨勢?
mvvm中 viewmodel該如何設計?
如何正確使用Vue.js的組件?

TAG:knockoutjs | MVVM | AngularJS | Vuejs |