WinJS基于ECMAScript 5,具有面向对象属性。
在使用WinJS进行Windows 8 App开发时,为了数据与界面分开,可以使用MVVM设计模式。
mvvm由model、viewmodel、view组成,model中主要用来存储数据、viewmodel负责对数据的各种操作、view负责数据的呈现。
在WinJS开发中,使用mvvm时很合适的,因为就像做网页一样。
首先定义一个viewmodel.js
(function () {
"use strict"
var shoppingItemsList = new WinJS.Binding.List();
var perferredStoresList = new WinJS.Binding.List();
WinJS.Namespace.define("ViewModel", {
UserData: WinJS.Binding.as({
//public member
homeZipCode: null,
getStores: function () {
return perferredStoresList;
},
addStore: function (newStore) {
perferredStoresList.push(newStore);
},
getItems: function() {
return shoppingItemsList;
},
addItem: function (newName, newQuantity, newStore) {
shoppingItemsList.push({
item: newName,
quantity: newQuantity,
store: newStore
});
}
}),
State: WinJS.Binding.as({
selectedIndex: -1
})
});
ViewModel.UserData.homeZipCode = "NY 10118";
ViewModel.UserData.addStore("Whole Foods");
ViewModel.UserData.addStore("Korognh");
ViewModel.UserData.addStore("Costco");
ViewModel.UserData.addStore("Walmart");
ViewModel.UserData.addItem("Apples", 4, "Whole Foods");
ViewModel.UserData.addItem("Hotdogs", 12, "Costco");
ViewModel.UserData.addItem("soda", "4 pack", "Costco");
})();
在这个viewmodel中现在只需要看UserData这个对象就可以了,其他的后面再说。
上面在定义viewmodel时,使用了namesapce,在WinJS开发中,使用命名空间可以减少全局变量的数量,也可以增加程序的阅读性。
定义UserData对象时,使用了WinJS.binding.as()方法,这个方法是将参数的对象作为一个可监察对象返回,也就是监察者模式在WinJS上的一个实现。需要注意的是,这个方法必须用在对象上,不可以用在属性上,用在属性上返回的只是一个静态对象,不是监察的。
使用监察者模式的好处就是,放对象的属性与界面的标签绑定之后,数据改变时,标签的内容也会改变,但是这个只是实现了数据从model到界面的单向流动,而当界面改变的时候,需要对数据也进行更新,这个就需要自己使用响应了实现啦。
对象属性与界面标签的绑定,可以使用下面的代码实现
<div class="win-type-x-large">
The zip code is :
<span data-win-bind="innerText: UserData.homeZipCode"></span>
</div>
在html文件某个标签中使用data-win-bind属性,进行声明,然后在对应的js文件中,使用WinJS.Binding.processAll(document.body, ViewModel);方法进行真正的绑定。第一个参数是dom对象,第二个是要进行绑定的对象。后面还有两个参数,有兴趣的朋友可以自己查看文档。
说完怎么从数据到界面的监测,下面说怎么从界面到数据的更新。
首先是界面中有一个输入框,可以让用户输入新数据
<div class="win-type-x-large">
<label for="newZip">Enter new zip code :</label>
<input id="newZip" data-win-bind="value: UserData.homeZipCode" />
<button id="newZipButton">Update Zip Code</button>
</div>
然后在对应的js文件中,使用下面的方法
WinJS.Utilities.query('#newZipButton').listen("click", function (e) {
ViewModel.UserData.homeZipCode = WinJS.Utilities.query('#newZip')[0].value;
console.log("zipcode ViewModel.UserData.homeZipCode");
});
对按钮添加了单击的响应操作,获取用户输入的内容,并更新数据。
WinJS.Utilities.query()方法是类似JQuery的实现。
最后说一个使用WinJS.binding.list()对象时候需要注意的点。
当我们的数据是数组这样的类型时,又需要使用这些数据对界面进行更新,那么使用WinJS.bingding.list对象是不错的选择。但是如果使用了这个list对象,那么在声明绑定的时候,就不可以使用像上面那种在标签中直接声明绑定到对象的某个属性,这样的声明式的绑定方法。
使用WinJS。Bingding.List 对象对界面进行更新时,需要在对应的js文件中使用代码对dom对象进行更新。
首先在html中声明下面几个标签
<h1 class="win-type-xx-lager">Left Full Container</h1>
<div class="win-type-x-large">
The last Item is <span id="listInfo">soda</span>
</div>
<div class="win-type-x-large">
<button id="addItemButton">Add Item</button>
<button id="removeItemButton">Remove Item</button>
</div>
然后在对应的js文件中
WinJS.Utilities.query('button').listen("click", function (e) {
if (this.id == "addItemButton") {
ViewModel.UserData.addItem("Ice Cream", 1, "Walmart");
} else {
ViewModel.UserData.getItems().pop();
}
});
var setValue = function () {
var list = ViewModel.UserData.getItems();
if (list.length > 0) {
document.getElementById("listInfo").innerText = list.getAt(list.length - 1).item;
}
};
var eventTypes = ["itemchanged", "iteminserted", "itemmoved", "itemremoved"];
eventTypes.forEach(function (type) {
ViewModel.UserData.getItems().addEventListener(type, setValue);
});
上面的代码首先为两个按钮添加了响应。
然后对viewmodel中UserData中的数据,只要数据有变动,就调用setValue()方法,对相应 的dom元素进行更新。
差不多就是这些,mvvm模式、Data Binding的基本使用。