http://url.cn/MhcbAc 礼包码:5lbckopvl4n ,这个地址是《Flex4权威指南》中的全部代码的下载地址,分享一下共同学习。
因为我暂时只能这样分享了,资源在我的115网盘里,可能还得需要注册吧。
一、VO包
1.值对象Product.as
package valueObjects {
[Bindable]
public class Product {
public var catID:Number;
public var prodName:String;
public var unitID:Number;
public var cost:Number;
public var listPrice:Number;
public var description:String;
public var isOrganic:Boolean;
public var isLowFat:Boolean;
public var imageName:String;
public function Product( catID:Number, prodName:String, unitID:Number,
cost:Number, listPrice:Number, description:String, isOrganic:Boolean,
isLowFat:Boolean, imageName:String ) {
this.catID = catID;
this.prodName = prodName;
this.unitID = unitID;
this.cost = cost;
this.listPrice = listPrice;
this.description = description;
this.isOrganic = isOrganic;
this.isLowFat = isLowFat;
this.imageName = imageName;
}
public function toString():String {
return "[Product]" + this.prodName;
}
public static function buildProduct( o:Object ):Product {
var p:Product;
p = new Product( o.catID, o.prodName, o.unitID, o.cost,
o.listPrice, o.description, ( o.isOrganic == 'true' ),
( o.isLowFat == 'true' ), o.imageName );
return p;
}
public static function buildProductFromAttributes( data:XML ):Product {
var p:Product;
var isOrganic:Boolean = ( data.@isOrganic == "Yes" );
var isLowFat:Boolean = ( data.@isLowFat == "Yes" );
p = new Product( data.@catID,
data.@prodName,
data.@unitID,
data.@cost,
data.@listPrice,
data.@description,
isOrganic,
isLowFat,
data.@imageName );
return p;
}
}
}
二、services包
1.CategoryService.as
package services {
import mx.collections.XMLListCollection;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.mxml.HTTPService;
public class CategoryService extends HTTPService {
[Bindable]
public var categories:XMLListCollection;
public function CategoryService(rootURL:String=null, destination:String=null) {
super(rootURL, destination);
this.resultFormat = "e4x";
this.url = "http://localhost:8080/toFlex/category.xml";
addEventListener(ResultEvent.RESULT, handleCategoryResult);
}
private function handleCategoryResult(event:ResultEvent):void{
categories = new XMLListCollection( event.result.category );
}
}
}
2.ProductService.as
package services {
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.mxml.HTTPService;
import valueObjects.Product;
public class ProductService extends HTTPService {
[Bindable]
public var products:ArrayCollection;
private var selectedCategory:Number=1;
public function ProductService(rootURL:String=null, destination:String=null) {
super(rootURL, destination);
this.resultFormat="e4x";
this.url="http://localhost:8080/toFlex/categorizedProducts.xml";
addEventListener(ResultEvent.RESULT, handleProductResult);
}
private function handleProductResult( event:ResultEvent ):void {
var productsArray:Array = new Array();
var resultData:XMLList = event.result..product;
for each (var p:XML in resultData) {
var product:Product = Product.buildProductFromAttributes( p );
productsArray.push( product );
}
products = new ArrayCollection( productsArray );
products.filterFunction = filterForCategory;
products.refresh();
}
public function filterForCategory( item:Product ):Boolean{
return item.catID == selectedCategory;
}
public function filterCollection( id:Number ):void{
selectedCategory = id;
products.refresh();
}
}
}
三、主页或叫主应用程序(FlexGrocery.mxml)包括controlbarContent和ShoppingView组件
FlexGrocery.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:views="views.*" xmlns:services="services.*"
creationComplete="handleCreationComplete(event)">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
<services:CategoryService id="categoryService"/>
<services:ProductService id="productService"/>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import spark.events.IndexChangeEvent;
private function handleViewCartClick( event:MouseEvent ):void {
bodyGroup.currentState="cartView";
}
private function handleCreationComplete(event:FlexEvent):void {
categoryService.send();
productService.send();
}
protected function list1_changeHandler(event:IndexChangeEvent):void
{
productService.filterCollection( event.target.selectedItem.categoryID );
}
]]>
</fx:Script>
<s:controlBarLayout>
<s:BasicLayout/>
</s:controlBarLayout>
<s:controlBarContent>
<s:Button y="10" label="Checkout" id="btnCheckout" right="10"/>
<s:Button y="10" label="View Cart" id="btnCartView" right="90" click="handleViewCartClick( event )"/>
<s:Button label="Flex Grocer" x="5" y="5"/>
<s:List left="200" height="52"
dataProvider="{categoryService.categories}"
itemRenderer="components.NavigationItem"
change="list1_changeHandler(event)">
<s:layout>
<s:HorizontalLayout/>
</s:layout>
</s:List>
</s:controlBarContent>
<s:Label text="(c) 2009, FlexGrocer" right="10" bottom="10"/>
<views:ShoppingView id="bodyGroup"
width="100%" height="100%"
groceryInventory="{productService.products}"/>
</s:Application>
controlBarContent使用呈现器为:NavigationItem组件
NavigationItem.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:layout>
<s:VerticalLayout horizontalAlign="center"/>
</s:layout>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<mx:Image
source="assets/nav_{data.name.toLowerCase()}.jpg"
height="31" width="93"/>
<s:Label text="{data.name}"/>
</s:ItemRenderer>
ShoppingView.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:components="components.*">
<s:layout>
<s:HorizontalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import cart.ShoppingCart;
import cart.ShoppingCartItem;
import events.ProductEvent;
import mx.collections.ArrayCollection;
import valueObjects.Product;
[Bindable]
public var shoppingCart:ShoppingCart = new ShoppingCart();
[Bindable]
public var groceryInventory:ArrayCollection;
private function handleViewCartClick( event:MouseEvent ):void {
this.currentState="cartView";
}
private function renderProductName( item:ShoppingCartItem ):String {
var product:Product = item.product;
return '(' + item.quantity + ') ' + product.prodName + ' $' + item.subtotal;
}
private function addProductHandler( event:ProductEvent ):void {
var sci:ShoppingCartItem = new ShoppingCartItem( event.product );
shoppingCart.addItem( sci );
}
private function removeProductHandler( event:ProductEvent ):void {
var sci:ShoppingCartItem = new ShoppingCartItem( event.product );
shoppingCart.removeItem( sci );
}
]]>
</fx:Script>
<s:states>
<s:State name="State1"/>
<s:State name="cartView"/>
</s:states>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<components:ProductList width="100%" height="100%"
width.cartView="0" height.cartView="0"
visible.cartView="false"
dataProvider="{groceryInventory}"
addProduct="addProductHandler( event )"
removeProduct="removeProductHandler( event )"/>
<s:VGroup height="100%" id="cartGroup" width.cartView="100%">
<s:List id="cartList"
dataProvider="{shoppingCart.items}"
includeIn="State1"
labelFunction="renderProductName"/>
<s:Label text="Your Cart Total: ${shoppingCart.total}"/>
<s:Button label="View Cart" click="handleViewCartClick( event )" includeIn="State1"/>
<mx:DataGrid includeIn="cartView" id="dgCart" width="100%">
<mx:columns>
<mx:DataGridColumn headerText="Column 1" dataField="col1"/>
<mx:DataGridColumn headerText="Column 2" dataField="col2"/>
<mx:DataGridColumn headerText="Column 3" dataField="col3"/>
</mx:columns>
</mx:DataGrid>
<s:Button includeIn="cartView" label="Continue Shopping" click="this.currentState=''"/>
</s:VGroup>
</s:Group>
四、cart包(包名如果改为services包可能会更容易理解,因为这个包里是业务逻辑对象,但是services包给了远程数据获取类了,在这里直接命名包名为所提供的功能未尝不可)
1.ShoppingCartItem.as 跟踪操作的商品,含商品对象、商品数量及小计金额,当数量发生改变时更改小计金额
package cart {
import valueObjects.Product;
[Bindable]
public class ShoppingCartItem {
public var product:Product;
private var _quantity:uint;
public var subtotal:Number;
public function ShoppingCartItem( product:Product, quantity:uint=1 ){
this.product = product;
this.quantity = quantity;
calculateSubtotal();
}
public function get quantity():uint
{
return _quantity;
}
public function set quantity(value:uint):void
{
_quantity = value;
calculateSubtotal();
}
private function calculateSubtotal():void{
this.subtotal = product.listPrice * quantity;
}
public function toString():String {
return "[ShoppingCartItem] " + product.prodName + ":" + quantity;
}
}
}
2.ShoppingCart.as 业务逻辑大部分在这里
package cart {
import mx.collections.ArrayCollection;
import mx.collections.IViewCursor;
import mx.collections.Sort;
import mx.collections.SortField;
import mx.events.CollectionEvent;
public class ShoppingCart {
[Bindable]
public var items:ArrayCollection = new ArrayCollection();
[Bindable]
public var total:Number = 0;
public function ShoppingCart() {//在构造器中使用ArrayCollection的排序功能
var prodSort:Sort = new Sort();
var sortField:SortField = new SortField( "product" );
prodSort.fields = [ sortField ];
items.sort = prodSort;
items.refresh();
items.addEventListener(CollectionEvent.COLLECTION_CHANGE, handleItemsChanged );//集合中的某一项发生变化,调用handleItemsChanged方法
}
public function addItem( item:ShoppingCartItem ):void {
if ( isItemInCart( item ) ) {
updateItem( item );
} else {
items.addItem( item );
}
}
public function removeItem( item:ShoppingCartItem ):void {
var cursor:IViewCursor = items.createCursor();//使用光标删除ArrayCollection数据,集合一定要事先排好序
if ( cursor.findFirst( item ) ) {
cursor.remove();
}
}
private function getItemInCart( item:ShoppingCartItem ):ShoppingCartItem {
var existingItem:ShoppingCartItem;
var cursor:IViewCursor = items.createCursor();//用光标查找ArrayCollection数据,集合一定要事先排好序
var found:Boolean = cursor.findFirst( item );
if ( found ){
existingItem = cursor.current as ShoppingCartItem;
}
return existingItem;
}
private function isItemInCart( item:ShoppingCartItem ):Boolean {
var sci:ShoppingCartItem = getItemInCart( item );
return ( sci != null );
}
private function updateItem( item:ShoppingCartItem ):void {
var existingItem:ShoppingCartItem = getItemInCart( item );
existingItem.quantity += item.quantity;
}
//还能指定ArrayCollection的filterFunction实现集合的过滤功能,此处没有使用此功能
private function calculateTotal():void{
var newTotal:Number = 0;
var existingItem:ShoppingCartItem;
for ( var i:uint=0; i<items.length; i++ ) {
existingItem = items[ i ] as ShoppingCartItem;
newTotal += existingItem.subtotal;
}
this.total = newTotal;
}
public function toString():String {
return "[ShoppingCart $" + total + "] " + items;
}
private function handleItemsChanged( event:CollectionEvent ):void {
calculateTotal();
}
}
}
五、events包,继承Event类,定制自己需要的事件对象
ProductEvent.as 自定义Event,增加属性使其能添加自己想添加的信息
package events {
import flash.events.Event;
import valueObjects.Product;
public class ProductEvent extends Event {
public var product:Product;
public function ProductEvent(type:String, product:Product ) {
super(type, true);
this.product = product;
}
public override function clone():Event{
return new ProductEvent(type, product);
}
}
}
六、components包(组件包),只要一谈到让组件的工作更具体化,就意味着要创建一个组件的子类。如将ShoppingView组件再细分为,{展示商品:[展示商品所用的数据集:ProductList.mxml,数据集使用的呈现器:ProductItem.mxml]},上面提到的ShoppingView、NavigationItem.mxml组件也是在components包中
ProductList.mxml 数据集,呈现器为ProductItem(并没有在呈现器中指定dataProvider而是在呈现器的父容器的父容器ShoppingView.mxml中指定dataProvider,上级容器指定能够达到松解耦合的目的)
<?xml version="1.0" encoding="utf-8"?>
<s:DataGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
itemRenderer="components.ProductItem">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Metadata>
[Event(name="addProduct",type="events.ProductEvent")]
[Event(name="removeProduct",type="events.ProductEvent")]
</fx:Metadata>
</s:DataGroup>
<?xml version="1.0" encoding="utf-8"?>
<s:DataRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="100%">
<fx:Metadata><!--<fx:Metadata>元数据标签,表示该对象会分派addProduct和removeProduct事件,类型同为events.ProductEvent-->
[Event(name="addProduct",type="events.ProductEvent")]
[Event(name="removeProduct",type="events.ProductEvent")]
</fx:Metadata>
<s:layout>
<s:HorizontalLayout/>
</s:layout>
<s:states>
<s:State name="State1"/>
<s:State name="expanded"/>
</s:states>
<fx:Script>
<![CDATA[
import events.ProductEvent;
import valueObjects.Product;
[Bindable]
public var product:Product;
private function addToCart( product:Product ):void {
var event:ProductEvent = new ProductEvent( "addProduct", product );
dispatchEvent( event );
}
private function removeFromCart( product:Product ):void {
var event:ProductEvent = new ProductEvent( "removeProduct", product );
dispatchEvent( event );
}
public override function set data(value:Object):void{//itemRenderer的原理就是针对dataProvider中的每一个数据项都创建一个呈现器的实例,而itemRenderer的data属性就会取得dataProvider中相应数据项的数据。
this.product = value as Product;//此处是转换value的类型,从Object转为Product
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:VGroup id="products">
<s:Label text="{product.prodName}" id="prodName"/>
<mx:Image scaleContent="true" source="assets/{product.imageName}"
mouseOver="this.currentState='expanded'"
mouseOut="this.currentState='State1'"/>
<s:Label text="${product.listPrice}" id="price"/>
<s:Button label="AddToCart" id="add"
click="addToCart( product )"/><!--先派发click事件,继而通过click处理函数派发addProduct事件-->
<s:Button label="Remove From Cart" id="remove"
click="removeFromCart( product )"/><!--先派发click事件,继而通过click处理函数派发removeProduct事件-->
</s:VGroup>
<s:VGroup includeIn="expanded" x="200" width="100%">
<s:RichText text="{product.description}"
width="50%"/>
<s:Label text="Certified Organic"
visible="{product.isOrganic}"/>
<s:Label text="Low Fat"
visible="{product.isLowFat}"/>
</s:VGroup>
</s:DataRenderer>
更正一下建项目时的顺序,前面写的可能不对,下面写的是自己想了想右写的。
(1)主界面
(2)远程数据获取对象(services包)
(3)将主界面细分为各个组件(components包)
(4)值对象(vo包)
(5)业务逻辑(services包)
(6)重构(events包会在重构时起作用,因为每一个事件对象都可以包含自己的信息,通过事件分发和监听来实现一些操作,比如加入购物车、从购物车中删除等,就会减少new 的使用,这样会达到松散耦合的效果。此外,Flex使用基于事件或者说事件驱动的编程模型,这就意味着事件决定应用程序的流程)
这些只是暂时看完前11课后的小总结,可能以后还会有更加好的重构方法,未完,再续。