2012年7月18日 星期三

Sencha Touch 2 : Model

一.Model功能
1.定義資料架構
model被用來定義在應用程式中所要使用的資料架構,也就是說定義好model內的資料欄位(field)將取得的資料包裝成model物件後,就可以用model所提供的方法來操作
2.與Store配合使用
model大多與store一起使用,當store使用proxy載入資料後,會將資料轉成model物件,model本身也可以定義proxy,自行載入資料,但比較不建議這樣使用,因Store可以透過Ext.getStore()讓store可以在各個地方使用,model則沒辦法,主要還是把model當作資料架構定義與資料內容驗證用
3.Ext.data.Model包含了四個部分 
  • Fields:欄位定義 
  • Proxies:設定取資料用proxy
  • Associations:設定model間關聯性
  • Validations:驗證
二.欄位(fields)
當由server取到json物件要儲存到model欄位
若要儲存到欄位的資料為物件,type可設定為auto
在tmpl內要取用欄位資料用{xxx.xxx}方式往下讀取即可

Ext.define('User', {
    extend: 'Ext.data.Model',
    config: {
        fields: [
            {name: 'id',   type: 'int'},
            {name: 'name', type: 'string'},
            {name: 'obj', type: 'auto'},
        ]        
    }
});

三.驗證Validations
對指定的欄位設定驗證規則
在validastions內可設定多條規則
每筆包含type:驗證項目,field:要驗證的欄位
type可使用的值為
  • presence:檢查是否有值,0是有效的,空值則無效
  • length:可設定最長(max),或最少(min)字元
  • format:檢查字串形式,用reg express檢查
  • inclusion:設定允許使用的字串
  • exclusion:設定不允許使用的字串
Ext.define('User', {
    extend: 'Ext.data.Model',
    config: {
        fields: [
            {name: 'id',   type: 'int'},
            {name: 'name', type: 'string'},
            {name: 'obj', type: 'auto'},
        ],
        validations: [
            { type: 'presence', field: 'id' },
            { type: 'presence', field: 'name', message: '不可空白'}                    
        ]    
    }
});

四.關聯Associations
設定好關聯性可以讓model內可包含其他的model
可以在取得資料後,把資料塞到各階層的model內
如果不使用關聯性設定,欄位的內容只是一個object
使用關聯性設定可以讓欄位內容是一個model
1.設定關聯性範例
Ext.define('User', {
    extend: 'Ext.data.Model',
    config: {
        fields: [
            {name: 'id',   type: 'int'},
            {name: 'name', type: 'string'}
        ],        
        hasMany: {model: 'Product', name: 'products'}
    }
});
代表User內有一個products屬性,這個屬性內儲存著Product Model的Array

2.使用關聯性範例
User.load(1, {
    success: function(user) {
        console.log("User: " + user.get('name'));
        user.posts().each(function(post) {            
            console.log(post.get('title'));//post本身即是一個model
            post.comments().each(function(comment) {//post內的comment也是一個model
                console.log(comment.get('message'));
            });
        });
    }
});    
3.當model有設定belongTo,就可以取得其上層model instance

Ext.define('User', {
    extend: 'Ext.data.Model',
    config: {
        fields: [
            {name: 'id',   type: 'int'},
            {name: 'name', type: 'string'}
        ],        
        hasMany: {model: 'Post', name: 'prosts'}
    }
});
Ext.define('Post', {
    extend: 'Ext.data.Model',
    config: {
        fields: [
            {name: 'id',   type: 'int'},
            {name: 'name', type: 'string'}
        ],        
        belongsTo: 'User'
    }
});
post.getUser(function(user) {//非同步,要透過callback取得user
    console.log('post: ' + user.get('name'))
});    

五.id屬性
若model內的data值有id,這id值也會被copy到model上產生internalId值
當model.getId()會取到這internalId值
若有用idProperty指定哪個欄位當id值,則該欄位會被copy到internalId
若資料內沒id值,也沒設定idProperty,就會用系統自己產生的id值

Ext.define("Stest.model.ItemModel", {
    extend: "Ext.data.Model",
    config: {
        idProperty: 'firstName',
        fields: [
            { name: 'firstName', type: 'string' },
            { name: 'lastName', type: 'string'}                   
        ]        
    }
});
注意:當作localStorage Store使用的model,不可使用id field,必須由系統產生
否則無法儲存到localStorage上

六.載入資料
model要執行load必須透過Class執行,且執行結果必須要是array,若不是,同樣需要在rootProperty內先處理
Ext.define("Stest.model.ItemModel", {
    extend: "Ext.data.Model",
    config: {
        idProperty: 'firstName',
        fields: [
            { name: 'firstName', type: 'string' },
            { name: 'lastName', type: 'string'}                
        ]      
    }
});

七.使用資料
  1. model.raw取到原始資物物件
  2. model.getData()取到修改過的資料物件
  3. model.get('欄位名稱')取到指定欄位值

Sencha Touch 2 : Store 載入資料的後處理

一.需要處理的狀況
當Store取得資料,目標是將資料轉成model Array以方便使用Store提供的功能如find,sorter filter等操作,可能遇到狀況
  1. 取得的資料為物件,只取物件中array的部份產生model array
  2. 載入的資料欄位需要先作一些修改處理,才能存到model內
在做這部份的處理,會使用到Store的rootProperty設定與Store的 load Listener

在載入資料時,rootProperty會先執行,然後才是執行load的listener
load listener內的資料已經是經過rootProperty處理過的資料

二.rootProperty
rootProperty是用在當由Server取得JSON物件資料,用來告訴Store在載入資料後,
由哪個節點開始解析放入model,通常會是節點名稱的字串值,也可以是一個function,
如果取得Server端的JSON已經是個Array,則rootProperty的設定是無效不會被執行到的


以下Store會以資料的users內容產生models
資料來源
{
    meta:{},
    users:[
        {},{}...
    ]
}

Store
Ext.define("My.store.MyStore", {
    extend: "Ext.data.Store",
    config: {
        model: "My.model.UserModel",            
        proxy: {
            type: 'ajax',                       
            reader: {
                type: 'json'              
            }
        },  
        rootProperty:"users"
    }
});

三.Load Event Listener
  1. 在資料載入後,load event會被觸發
    通常對要存入model的欄位值要做改變,可以在load event內做,也可以在rootProperty內處理,
    但最好統一在load event內做,因為如果資料來源是array,rootProperty並不會被執行到,可能會造成錯誤
  2. load evnet內會接收到records 與store參數,要對資料做處理可以使用records這或store來操作都可
  3. load event被觸發時,取得的records是該次fetch取得的資料,而非總資料量

四.回傳值為Array的處理範例
rootProperty不需設定,只要在listener load內處理所要的變化

Ext.define("My.store.MyStore", {
    extend: "Ext.data.Store",
    config: {
        model: "My.model.UserModel",            
        proxy: {
            type: 'ajax',                       
            reader: {
                type: 'json'              
            }
        }
    }
    listeners:{
        load:function(store,records,_success,operation,opts){
            for(var i=0;i
                records[i].set('uid',records[i].get('id'));
                delete records[i].getData().id;
            }
        }
    }    
});

五.回傳為物件的處理方式
rootProperty設定回傳array部份,其他值的變化由load event listener處理

Ext.define("My.store.MyStore", {
    extend: "Ext.data.Store",
    config: {      
        model: "My.model.MyModel",    
        proxy: {
            type: 'ajax',                
            reader: {
                type: 'json',
                rootProperty:function(data){
                    return data.users                    
                }            
            }
        },
        listeners:{
            load:function(store,records,_success,operation,opts){                
                for(var i=0;i
                    records[i].set('uid',records[i].get('id'));
                    delete records[i].getData().id;                    
                }
                //---兩種方式都可以----
                store.each(function(record, index){
                  record.set('index', index);
                },store)
            }
        }
    }
});    

六.處理過後的資料使用
  1. Store如果被加工過,那取資料要由model.getData()取,不要由model.raw取
  2. 要將資料放到其他store內,不要直接將records(models array加進去)  而是由所有model取出資料,放data array而非models array比較安全


listeners:{
    load:function(store,records,_success,operation,opts){
        var _objs=[];
        for(var i=0;i
            records[i].set('uid',records[i].get('id'));
            delete records[i].getData().id;
            _objs.push(records[i].getData())
        }
        var anotherStore=Ext.getStore('AnotherStore');
        localStore.add(_objs);    
    }
}    

2012年7月16日 星期一

Sencha Touch 2 : Store 操作

一 Store用途
Store用來儲存資料,並提供對資料作sorting,filtering與query的功能
Store利用Proxy與Server連線取得資料,Proxy內的Reader解析取得的資料
會對取得的資料再加工,然後將所有解析完資料轉成model物件
儲存在Store內以供使用

二.Store定義
1.storeId:
當store有設定storeId,即會被註冊到storeManager,
若沒設定會預設以該Store的Class Name當storeId
在Project的任何地方都可以透過
Ext.getStore(storeId)來參考到該store做操作
Ext.data.StoreManager.lookup('myStore')一樣

Ext.create('Ext.data.Store', {
    model: 'SomeModel',
    storeId: 'myStore'
});
var store = Ext.data.StoreManager.lookup('myStore');
2.model
設定載入的資料要以哪種model物件型態儲存
3.proxy
設定要使用哪種Proxy與Server溝通取得資料
4.clearOnPageLoad
設定當載入資料後,是否將原有在Store內的資料清掉,預設值為true,
若要多次載入多頁分頁資料,則這裡要設定true
5.sample
Ext.define("MyApp.store.MyStore", {
    extend: "Ext.data.Store",
    config: {      
        model: "MyApp.model.ItemModel",      
        proxy: {
            type: 'ajax',                  
            reader: {
                type: 'json',              
                rootProperty: function(data) {
                    ...
                    return data;                             
                }              
            }
        },      
        clearOnPageLoad:true,
        listeners:{
            load:function(store,records,_success,operation,opts){                
                .....        
            }
        }      
    }  
});
三.Store功能
1.sorters:設定這個Store內資料的排列規則
設定以哪個欄位來做排序
例:會依照artist欄位由大到小排列
sorters: [{
    property: 'artist',
    direction: 'DESC'
}]

DESC:由大到小
ASC:由小到大

2.filter:設定要取出store內的哪些資料
例:只有欄位name值=Ed的資料才會取出來
filters: [{
    property: 'name',
    value   : 'Ed'
}]
3.groupField,groupDir,grouper
4.sample
Ext.create('Ext.data.Store', {
    model: 'User',
    sorters: ['name', 'id'],//取得的資料會以name,id依序排列
    filters: {
        property: 'name',//只有欄位name值=Ed的資料才會取出來
        value   : 'Ed'
    },
    groupField: 'age',//以age欄位來group資料,
    groupDir: 'DESC'//用由大往小方式排列
});    

四.Store載入資料
1.使用data,直接設定資料內容與使用MemoryProxy
直接把資料寫在store內,這時會把data內的資料,直接
轉成model,這時在Store內不需要使用到proxy,但若需要將資料先處理過
再轉成model使用,則可以用MemoryProxy來處理

注意:MemoryProxy只能對array做一次性的讀取與處理,而無法對現存的array做add與update動作

var store = Ext.create('Ext.data.Store', {
    autoLoad: true,
    model: 'User',
    data : data,
    proxy: {
        type: 'memory',
        reader: {
            type: 'json',
            root: 'users'
        }
    }
});
2.load(options,scope)載入資料
參數
options:設定選項,這是一個非必填的Ext.data.Operation物件
scope:非必填,設定在這function內的this會指到哪個物件
預設是this(也就是執行store.load所在的view)

3.loadPage(page,options)分批載入的資料不斷累積
  1. page:Number,要載入的分頁,這是必填欄位,但如果你並未在options內用設定使用到start,end..等分頁資訊,這裡可以隨便填一個數字,如1即可
    options:設定選項,這是一個非必填的Ext.data.Operation物件
  2. clearOnPageLoad要設成false,否則前次載入的資料會被清除
  3. 建議不要使用sorter功能,因為新載入資料後,全部資料會被重新排序,有可能會影響之前顯示的順序
4.Ext.data.Operation物件
在執行load或loadPage都會使用到options物件來設定
最常用的會是像設定callback,在載入完成後會被自動觸發

store.load({
    callback:function(records, operation, success){}
})


五.使用Store內的資料
1.當執行load取回傳資料一定要是array
若資料來源本身並非array,則要在reader內的root內先行處理
2.使用index找model
會找到位在index的model
store.getAt(index)
3.使用指定欄位值找model
會找到fielName值=value的那個model
store.findRecord(fieldName,value)
4.注意
取到model後,可以透過model.getData()model.raw來使用資料
兩者都是取得Object物件,model.raw是載入的最原始資料內容
如果在載入資料後有使用rootProperty或是load event對資料處理過
那一定要取model.getData()來應用
model.raw是原始資料,可能會出錯

4.取得store資料數量
store.getData().length(取得目前資料數量)

store.getCount()
5.使用在callback內取得的資料
在執行load或loadPage時會設定Ext.data.Operation物件
使用options物件設定callback,在資料載入完成後,
即可在裡面做一些處理
callback會接收到3個參數

  • records:
    當次所取得的資料array,如果在clearOnPageLoad=false
    情況下當次取得的資料並不一定會完全等於store內的資料
  • operation:Operation物件本身
  • success:boolean值


var _url="server/proxy.php?type=song&songid="+id;
Ext.getStore("SongFileStore").getProxy().setUrl(_url);         
Ext.getStore("SongFileStore").load({
    callback: function(records, operation, success) {
        console.log(records[0].data.url);            
    },
    scope: this        
});


六.Store應用
1.store與listView綁定
只要在listview設定使用哪個store
當該store更動時,listview會自動update不需自己設定

var list={            
    xtype:'itemList',
    itemId:'list',
    store:Ext.getStore('GroupItemsStore'),
    listeners:{
        itemsingletap:{
            fn:this.onClickItem,
            scope:this
        }                
    }           
}


2.callBack scope
在執行store.load設定其callback時
scope若設成this,則callback內部的this會指到這程式所在的View Class
若scope指到store上,則this就會指到這個store

Ext.getStore("SongCardStore").load({
    callback: function(records, operation, success) {
        //console.log('load song card compllete='+)
        console.log('this');
        console.log(this);
    },
    scope: Ext.getStore("SongCardStore")
});    

2012年7月11日 星期三

Sencha Touch 2 : LocalStorage Proxy使用

一.功能
建立使用LocalStorage Proxy的Store
讓你可以用store來操作localStorage的存取

二.建立Model
要當作localStorage操作用的Store,所使用的model,強制必須使用系統產生的id值
因此會有以下幾個限制
1.不可使用idProperty
idProperty是用來指定特定field當若id值用,因此在這裡不可使用
2.資料欄位不可以有id
因為必須由系統幫每筆model資料產生id屬性值,所以要放在model內的資料不可用id當作屬性名稱

Ext.define("Test.model.ItemModel", {
    extend: "Ext.data.Model",    
    config: {       
        fields: [
            { name: 'uid', type: 'string' },
            { name: 'fName', type: 'string' },
            { name: 'lName', type: 'string'}                   
        ]      
    }
});

三.建立Store
1.設定storeId
可以在操作時使用Ext.getStore(storeId)來參考到這store
2.設定proxy
設定type:'localstorage'即為使用LocalStorage Proxy
設定id值,這id值會當作在localStorage內用來在localStorage內產生真正儲存的變數名稱


Ext.define("Test.store.ItemStore", {
    extend: "Ext.data.Store",
    requires:['Ext.data.proxy.LocalStorage'],
    config: {
        model: "Test.model.ItemModel",
        storeId:'hahaha',      
        proxy: {
            type: 'localstorage',
            id  : 'mylocal'
        }      
    }
});

四.儲存
當加入資料到store,產生model,會自動在model的資料內插入id屬性,也會在model上產生一個internalId屬性

1.指令
store.add([{..},{...}]) 加入資料
store.sync() 寫到localStorage上

2.實體儲存內容
實體儲存分成兩個部份,
一個是以設定的proxy id值當作變數,用來儲存所有的資料id

proxy id設定為mylocal
則會實際在localStorage內產生
localStorage.mylocal='1,2,3,4..'
這些id是系統在將每筆資料建立成model時,自動產生插入的

另一部份真正資料儲存在
以proxy id與model id所組成的變數內

localStorage.mylocal-1="{....}"
localStorage.mylocal-2="{....}"
.....

五.讀取
要將資料由localStorage載入store內
store.load()
若原本store內有資料,但localStorage內是空的,
則會把原本store內資料清掉

五.清除資料
1.清除store資料
store.removeAll();
2.清除localStorage資料
store.getProxy().clear()



Sencha Touch 2 : 安裝與使用

一.Ubuntu上開發環境安裝
1.下載Sencha Touch:sencha-touch-2.0.1.1
http://www.sencha.com/products/touch/download/2.0.1.1/
2.下載SDKTool:SenchaSDKTools-2.0.0-beta3
http://www.sencha.com/products/sdk-tools/download/
3.改為可執行檔
chmod +x SenchaSDKTools-2.0.0-beta3.run
4.執行安裝
sudo ./SenchaSDKTools-2.0.0-beta3.run
5.加入環境變數
sudo gedit .bashrc
加入PATH='/opt/SenchaSDKTools-2.0.0-beta3'

二.建立Project
1.建立工作目錄project/
建立作目錄,並將下載的sencha-touch-2.0.1.1
解壓縮到project目錄下
/project/sencha-touch-2.0.1.1/
2.建立專案
切換到sencha-touch-2.0.1.1下 執行
sencha app create 專案nameSpace ../專案目錄名稱

sencha app create Oz ../oz_app
會建立專案目錄
/project/oz_app
3.專案架構
app:所有要開發的程式都放在這裡
sdk:sencha touch 使用的sdk
resource:專案使用的css與圖檔放在這裡
app.json:架構上使用microloader,在這檔案設定要使用的css,js等相關路徑設定
            與專案輸出的設定
app.js:App程式進入點
packager.js:這是要將整個project package成App時的設定檔
4.app.json設定檔
基本需要設定的內容
1."js":設定要使用的js檔案路徑,以供microloader載入
預設sdk會使用sencha-touch.js,但若在專案內有用到Component
例如Select,會需要改用sencha-touch-all.js否則comonent會跑不出來
"js": [
    {
        "path": "sdk/sencha-touch.js"
    },
    {
        "path": "app.js",
        "update": "delta"
    }
]
如果還會使用到其他的js檔案要載入,在這裡可以加進去
2."css":
專案裡預設使用的css是由compass產生的css,修改請利用compass修改後產生css
如果要加載其他的css檔案可以在這裡加入
"css": [
    {
        "path": "resources/css/app.css",
        "update": "delta"
    }
]
3. "url" build的時候需注意app.json內的url需要設定index.html的路徑 若在本機上設定為 "url": "http://localhost/xxxx/index.html",
三.Build專案
當專案完成,會是由許多的js檔案組成,透過build的程序,可以將所有JS檔案
build成單一壓縮過的js檔
1.指令
進入project目錄 執行
sencha app build testing|production|package|native
2.檔案目錄
依照build設定的參數不同會在的build中產生不同的目錄
my_app_project/build/
my_app_project/build/testing/ 測試用,較方便debug
my_app_project/build/production/ 用來封裝phonegap
my_app_project/build/package/ 放到wb上直接使用
my_app_project/build/native/ 產生native App
常用的會是build成 production,所build出來的版本可以放到web上使用 也可以拿到phonegap上去封裝成APP
3.注意事項 在各個js內的Require一定要明確把有用到的Class寫進去,否則很容易發生編譯錯誤 四.使用線上 PhoneGap產生App 1.使用production來build
產生的production目錄壓縮成zip檔案
2.連線PhoneGap
https://build.phonegap.com/apps#add-application 上傳zip檔,即可線上產生App檔案

五.Delta Cache機制 在app.json裡預設我們對js與css檔案的update設定了delta機制 當有資料更新,舊資料會被放在archive目錄下 在各版本間產生delta client會下載delta資料去更新其localStorage內容讓他保持最新 當在online狀態micro-loader會去檢查資料(json type infomation)

但delta機制有可能在更新後造成app無法執行 此時只要清除localStorage即可
localStorage.clear() 

2012年7月6日 星期五

Mobile Web Debug工具

目前 Adobe Shadow還不提供Linux版的工具
如果在Linux上開發還有一些其他的debug方法
一.Chrome USB DEBUG
1.環境需求
電腦:需安裝Android SDK
Device:Android 4.0以上版本+安裝Chrome
2.流程
1.打開Android上 Chrome的 usb debug
2.device usb連接電腦
3.電腦上在cmd下執行
adb devices 檢查是否有device抓到
如果沒有看到device,可試著執行
adb kill-server
然後重新插入device
4.電腦上執行
 adb forward tcp:3138 localabstract:chrome_devtools_remote
5.電腦上打開chrome開啟網頁 localhost:3138 會顯示清單,選取要debug的頁面.如果沒有請refresh一下 6.點選要debug的頁面 即可對device做debug
二.Weinre Adobe Shadow是針對Weinre再包裝的產品,可以直接在電腦上安裝weirne使用 PC環境設定 1.安裝 需先安裝nodejs與npm再以npm安裝weinre

npm -g install weinre
2.執行weinre 設定使用的ip與port 執行
weinre --hostPort 1234 --boundHost 192.168.11.80
使用 1.device端 使用chrome開啟:http://192.168.11.80:1234 頁面上找到target demo,click
2.pc端 使用chrome開啟:http://192.168.11.80:1234 頁面上找到 Access Point/debug client user interface,click 開出畫面 看到target 有連結 click即可使用 參考網頁: http://kuro.tw/blog/2012/02/21/weinre-debug-mobile-web
三.PhoneGap線上weinre debug 1.開啟 http://debug.phonegap.com/ 2.依照步驟,輸入自訂的id並取得script tag 插入要debug的網頁內 3.開啟 在電腦的Chrome開啟 http://debug.phonegap.com/client/#自訂id

RequireJS對Backbone.js 做optimization

開發完成的Backbone.js Project包含了一堆的js檔案
可以使用RequireJS最佳化,將所有JS檔案壓縮成一個
一.準備工作
1.安裝nodejs
執行optimization 需要使用nodejs執行
下載與安裝
2.下載r.js檔案
這是用來執行工作的nodeJS Script檔案
下載
3.建立profile.js
檔案關聯設定檔

二.檔案架構
要執行最佳化工作是
nodejs以profile.js當作執行設定檔,來執行r.js,
請建立一個build的目錄來放置r.js與profile.js
build目錄不要放到backbone project js目錄下
檔案架構可以是
project/build/(放r.js與profile.js)
project/js/(所有專案內的js檔案)

三.profile.js的設定
1.baseUrl: 為profile.js所在目錄算起 要找到main.js的目錄參考
例如 baseUrl:../js/
2.out:要輸出結果的檔案名稱與路徑
例 out: "../js/main.min.js",  
3.paths:將main.js下設定的paths copy過來再加上require的路徑參考

paths : { 
  _loader:'utils/loader', 
  _$ : 'libs/jquery/jquery',  
  ...
  requireLib:'libs/require/require-min'       
}
4.include 設定requirejs的參考
  例
  include:'requireLib'
5.sample
({
    baseUrl: "../js/",
    name: "main",
    out: "../js/main.min.js",
    paths : {    
        _loader:'utils/loader',    
        _$:'libs/jquery/jquery',        
        _Underscore : 'libs/underscore/underscore',
        _Backbone : 'libs/backbone/backbone',
        ...
        requireLib:'libs/require/require-min'    
    },    
    include:'requireLib'
})  

四.執行
node r.js -o profile.js

五.網頁上使用
未作最佳化前使用
 <script data-main="js/main" src="js/libs/require/require.js"></script>  
最佳化後使用
 <script src="js/main.min.js"></script>  



 


2012年7月5日 星期四

Backbone.js使用RequireJS

一.說明
開發Backbone.js Project,每個Model,View都會是一個個的JS檔案
也會因使用到其他外部Library或是關連到其他Model
而讓各個JS間有一些關聯性
使用RequireJS來將裝Backbone的各個JS檔案都包裝成module,
不僅可以讓每個module切的更乾淨,同時還可利用
RequireJS的Optimizer將所有JS檔案package成單一JS檔案

二.檔案與目錄架構
main.js
app.js
router.js
text.js
order.js
views/
models/
collections/
templates/
libs/    

三.檔案架構說明

  1. main.js : project的進入點
  2. app.js : 初始化App要使用的所有物件instance,與網頁node相對應
  3. router.js : project controller,使用者url經過router處理,呼叫對應要執行的function
  4. text.js與order.js是RequireJS的Plugin,若有用到則放在這裡
  5. views/,collections/,models/ : Backbone產生的各個物件,包成Module後,分別放入各個相關目錄內
  6. templates/ : 要提供給view render使用的html樣板檔案放在這目錄下
  7. libs/ : 會用到的各種外部resource lib放在這裡,如jQuery...


四.main.js
RequireJS的程式進入點是main.js
在main.js內包含了兩個區塊,一塊在做project設定,一塊在做初始要執行的工作

1.設定
設定路徑別名
baseUrl : 設定所有js找檔案的root節點,
          預設是main.js所在路徑,
paths   : 將整個project內會用到的檔案或路徑,
          在這裡設定別名以方便在module中使用,
          使用上以baseUrl下的路徑書寫即可    
urlArgs : 可在runtime時替所有js都加入queryString,
          避免JS Cache

require.config({    
    paths : {    
        _loader:'utils/loader',    
        _$ : 'libs/jquery/jquery',
        _m:'models',        
        ....
    },    
    urlArgs: "ver=0.0",
});

2.要立刻執行的工作
通常會在這個block內,會有兩個部份會被初始化
1.global info
  把在project內屬於多個物件要共同監聽使用的
  model或collection在這裡new出instance,並設定到App內
  讓所有要用到的物件可以參考到
2.App
  整個App的主要架構檔,也在這裡產生instance

require(['order!_$','_Backbone','order!_m/InfoModel','order!_c/StoresCollection','order!_app'],function($,Backbone,InfoModel,StoreCollection,App) {        
    var info=new InfoModel();
    var stores=new StoresCollection();
    var citys=new CityCollection();
    Backbone.emulateHTTP = true;
    Backbone.emulateJSON = true;
    App.initialize({
        info:info,
        stores:stores        
    });        
});


五.Module define定義語法
1.
[]內設定在這Module內要關聯使用的module檔案路徑,在function內則會取到對應的物件可以
在Module內使用
define(['_Underscore','_backbone','_$'],function(_,Backbone,$){
    return {
    
    }
})

2.
在function內帶入require,就可以在module內使用require來載入其他的module
define(function(require){
    var $ = require('_$'),
        _ = require('_Underscore');
    return {
    
    }    
})

六.Module類型-instance模式
當你所定義的module在Project內,需要是一個唯一的singleton
例如App或是Router,在整個專案中都會是只有唯一的一個
次時所定義的Module回傳的會是一個instance而非Backbone Class

1.語法
define([],function(){
    return {
    ....
    }
})
2.Router sample
將原Backbone Router的功能隱藏在自訂的Module內,
定義
XXRouter.js
define([],function(){
   var MyRouter = Backbone.Router.extend({})
   return {
       myRouter: null,
    initialize: function (options) {
        this.myRouter = new MyRouter(options);                
    },
    navigate: function (path) {
        this.MyRouter.navigate("#" + path, true);
    }
}
})
使用
XXRouter.initialize()

3.App Sample
載入後直接取得一個instance物件
定義
App.js
define([],function(){
    return {
        initialize: function (options) {},
        ......
    }
})
使用
App.initialize();


七.Module類型-Class模式
當你所定義的module是屬於Project內的model,view或collection
你所定義的module回傳的會是Backbone的Class
1.語法
App.js
define([],function(){
    return {
       initialize: function (options) {},
        ......
    }
})
2.Backbone View sample
定義
MyView.js
define(['_backbone'],function(Backbone){
    return Backbone.View.extend({
        initialize:function(){},
        .....
    })    
})
使用
var myView=MyView();