2012年11月29日 星期四

2012 簡單生活節 手機版節目表


這禮拜就是2012 SimpleLife 簡單生活節
整個華山同時有四個舞台的音樂演出
前兩屆 每次去總覺得要一直翻紙本的節目表
有點麻煩
在公司用mobile web做了簡易的手機版演出節目表
使用了AppCache 只要開啟過,離線也可正常使用
start
home

可以查詢兩日各舞台的演出節目
可即時查詢各舞台正在進行的演出


簡易的歌手介紹
http://simplelife.streetvoice.com/m/

Heart of Gold


從小唱片音響一直都是家裡重要的設備
老爸喜歡聽台語歌
喜歡聽日本歌
架上一落一落的黑膠唱片
我總是在裡面找著那些布袋戲的主題曲
然後學著我爸 放起了唱片

國中以後 有機會跟老爸去唱片行
他買了日本歌買了洪榮宏
我也有機會夾帶了一張羅大佑

在老爸的那一大疊唱片中
很難得的看到一張英文合輯
這看起來 不像是老爸聽的音樂
可能是小叔叔在家裡留下來的
這是第一次聽到了Neil Young的Heart of Gold
高中開始玩吉他
歌本裡 也一再的看到這首歌

一直到失戀的那年
才彷彿在Neil Young的音樂中 找到救贖
靠著一張一張的CD 一首一首的歌曲
走過苦悶的那一年


2012年11月5日 星期一

Git多帳號登入

在使用GitHub或BitBucket服務時,使用ssh登入是最快的方式
要如何在一台電腦上使用不同的帳號登入
一.產生各自帳號的SSH Key
執行
ssh-keygen -C "youremail@xxx"
預設會儲存為id_rsa 的key,不同的email產生key請設定使用不同檔名儲存

二設定ssh config
在~/.ssh/目錄下產生config檔
在config內設定不同host指定使用不同的ssh key

Host PeterBitbucket
HostName bitbucket.org
User git
IdentityFile ~/.ssh/peter_id_rsa
IdentitiesOnly yes

Host OzzyBitbucket
HostName bitbucket.org
User git
IdentityFile ~/.ssh/ozzy_id_rsa
IdentitiesOnly yes

三.設定remote
在要使用的git repos設定remote
原本設定
git remote add git@bitbucket.org:ozzy/myrepos.git
改用以下方式設定
git remote add OzzyBitbucket:ozzy/myrepos.git
另一個帳號
git remote add PeterBitbucket:peter/myrepos.git
讓不同的帳號使用不同的ssh key連線

2012年9月21日 星期五

簡易的git操作使用

git功能相當多,這裡只列出最基礎使用部份
一.環境安裝
  1. window
    到以下網址下載安裝
    http://code.google.com/p/msysgit/downloads/list?q=net+installer
    http://git-scm.com/downloads
  2. ubuntu
    sudo apt-get install git
    
二.名詞說明
  1. repostory
    有版本控制功能的目錄
  2. local remote
    local是自己的repos,主軸為master,若有分支,就會有相關branch名稱
    remote是遠端的repos,通常在多人同時維護一份程式碼的狀況
    每個人都會有一個local的repos,大家都會對應到同一個remote做
    大家的版本共同管理,預設的remote名稱是origin
  3. stage ,unstage
    把檔案加入到stage,就是讓這些檔案會在版本控制的範圍內
  4. push,pull
    pull是由remote將檔案拉下來到local上
    push是將local檔案放到remote上
  5. commit,checkout
    做commit的動作就是產生一個新的檔案版本
    checkout就是切換到指定的版本或是分支

三.本機檔案版本控制
  1. 目錄初始化
    會產生一個.git目錄,讓該目錄成為一個repostory
    在目錄下執行
    git init
    
  2. 查看目前repostory的狀態
    檔案是否有更動,是否有檔案被加到stage,是否尚未commit
    等相關狀態都可以使用這指令看到
    git status
    
  3. 查看已儲存的版本(comit)清單
    git log
    
  4. 加檔案到stage
    加入指定檔案
    git add filename
    
    全部有異動的都加入
    git add .
    
  5. 刪除檔案
    git rm filename
    
    刪除目錄
    git rm -rf dirname
    
  6. 將已經加入stage的檔案移到unstage
    git reset HEAD filename
    
  7. 產生版本
    git commit -m "xxx"
    
  8. 回復到指定版本
    git reset -hard HEAD~1
    
    數字代表回復到前幾個版本
四.與遠端Remote做版本控制
  1. 將遠端的repos複製到local
    執行指令後,會將remote的目錄,複製到目前這個目錄下
    git clone 遠端目錄
    
  2. 設定要同步的遠端remote
    local respos 加入remote後,就可以把資料放到remote上,
    或是由remote 下載回來
    git remote add  aliasName remote路徑
    
  3. 查看目前所有的remote
    local respo上可以同時設定多個remote
    git remote -v 
  4. 由remote上取回最新檔案
    git pull origin master
    
  5. 將local檔案上傳到remote
    git push origin maste
    
五.修改檔案後更新流程
當你已經修改了檔案要放到remote上,也許remote上的檔案,在這過程中已經被別人更新做
以下流程處理
  1. 先把自己的修改內容放到暫存區
    git stash
    
  2. 由remote取回最新檔案
    git pull origin master
    
  3. 合併
    git stash apply
    
    把自己放在暫存區已改過的檔案與最新拉回來的檔案merge在一起,
    若有衝突的地方,系統會自動在差異處加入註解,
    修改好再儲存
  4. 重新把檔案加入到stage
    git add .
    
  5. 產生版本
    git commit -m xxxx
    
  6. 傳回remote上
    git push origin master

六.使用Github當作remote
  1. 選擇連線方式
    在你要clone的repos上可以看到有提供ssh或是http連線方式
    提供不同的連結網址,使用http連線,每次會要求輸入連線帳號密碼
    (就是github帳號密碼)
    若使用ssh則可直接連線,但須先設定ssh key
  2. 設定ssh key
    參考https://help.github.com/articles/generating-ssh-keys
    產生ssh key並貼到github個人資料頁內,即可使用ssh直接連線
七.使用Dropbox當remote
在指定的dropbox目錄上執行
git init --bare
該目錄即可成為一個git remote

2012年9月17日 星期一

使用CoffeeScript 建立nodeJS Class與使用

一.單一檔案單個Class
1.定義class檔案
寫好class檔案,以module.exports輸出
file:myclass.coffee
class MyClass
    constructor:(@name)->
module.exports=MyClass
2.使用
require參數是實體檔案的名稱,同目錄下用./來設定路徑
可以用不同的名稱來接收require的回傳值(Class)
Rocker=require('./myclass')
rocker=new Rocker()

二.單一檔案多個Class
1.定義class檔案
好class檔案,以module.exports輸出
file:myclass.coffee
class MyClass
    constructor:(@name)->
class MyClass2
exports.Rocker=MyClass
exports.Tester=MyClass2
2.使用
MyRocker= require('./myclass').Rocker
MyTester= require('./myclass').Tester
rocker=new MyRocker('oz')

2012年8月16日 星期四

HTML5 Application Cache

一.說明
HTML5提供了Application Cache機制,可以讓靜態檔案Cache在Client端
減少對Server的Request,加速頁面載入,當網站上資料有異動,需要客戶端
更新Cache資料,也可以很簡易的做到,進一步還可以達到離線閱讀的目的

二.原理
要使用了Application Cache,必須在網站上加上一個manifest檔案
manifest檔案內設定了要cache的檔案清單,當Client連線後會儲存保留
menifest檔案在Client端,每次連線一定會去比對Client端的manifest檔案與
Server端上的manifest檔案是否有異,若有異動,則會重新由Server讀取檔案儲存到Client的Cache,否則就會去直接讀取Client端的Cache顯示頁面資料

三.Web Server上需要的設定
在Web Server上需要對manifest的檔案類型做MIME Type設定
副檔名可以自訂
通常會是用.manifest 或 .appcache
例 在Apache Web Server設定加上
AddType text/cache-manifest .manifest

四.網頁上使用
 <html manifest='cache.manifest'>  
在所有會成為進入點的網頁,都需要加入設定指向manifest檔案

五.manifest檔案設定內容
CACHE MANIFEST 必要的第一行
CACHE:
區塊設定要cache的檔案清單  
NETWORK:
區塊設定一定要由網路讀取的清單  
FALLBACK:
區塊設定當讀取失敗,要轉向使用哪個替代內容顯示

CACHE MANIFEST
#ver 0.0.1
CACHE:
index.htm
/js/main.min.js
/css/app.css
/img/btn_img.png
NETWORK:
*
FALLBACK:

六.注意事項
  1. 更新
    要做任何檔案異動,除了檔案本身更動外,一定要讓manifest有所變化,否則系統只會一直讀取到Cache的資料,通常可以在manifest內加入一個版號宣告,只要有更動,客戶端即會自動更新Cache
  2. 不使用cache
    Application Cache與Browser一般的Cache暫存並不相同,並無法透過Browse的F5來清除, 要讓網頁不使用cache,必須透過刪除manifest內CACHE清單來達到
  3. 刪除manifest檔案
    直接刪除Server上的manifest檔案,也會讓Client不使用Cache
  4. 不要使用舊有的防檔案cache機制
    通常會在讀取如js檔案會加上一個版號來控制檔案cache
     <script scr="xx.js?ver=1.0"></script>  
    
    使用Application Cache請不要再使用這樣的手法,把Cache的管理都交給manifest處理即可

2012年8月6日 星期一

Sencha Touch 2 : 在View內使用html,tpl與itemTpl

在View裡除了使用內建的Compontent外,若需要產生html來當作View的內容
可能會在View的Config內用到以下幾個3種Tag
一.html
直接將html內容放到view內,若有需要被操作的物件是以html產生,建議以此方式放入可使用
1.String
例 字串array會自動使用join串接
html:[            
    "this html block..........",
    "kkman"
].join('')         

2.HTMLElement
例 array需以join('')串接,否則會被當成整個字串顯示
html:[
    "<div>this html block..........</div>",
    "<hr/>",
    "<div>hello</div>"
].join('')
3.Ext.Element ??

二.tpl
當為動態資料產生的內容,利用setData傳入資料與tpl產生view的html內容,通常會在一般的view內使用
一定要有執行setData(),tpl才會被render產生html
1.String
tpl:"<div><div>Hello me</div><div>{name}</div><div>{rock}</div></div>"

tpl:[
    "<div>",
    "<div>Hello me</div>",
    "<div>{name}</div>",
    "<div>{rock}</div>",
    "</div>"
].join('')
3.Ext.Template[]
設定tpl的動作一定要在執行setData前完成,也就是說可以設定在config的tpl
或是在initial程序內執行設定(在setData前設定好)
例 在config內設定
tpl:new Ext.Template("<div>Hello {name}.</div>")
例 在initial程序中使用
this.setTpl(new Ext.Template("<div>Hello me {name}.</div>"))

4.Ext.XTemplate[]

在initial內執行
this.setData([
    {
        name:'ozzy',
        type:'metal'
    },
    {
        name:'linda',
        type:'Rock'
    }
]);
在config內設定
tpl:new Ext.XTemplate(
   '<tpl for=".">',
        '<p>{name}</p>',
        '<p>{type}</p>',
        '<hr>',
    '</tpl>'
)
三.itemTpl
只有在List View可以使用,會將List View所關聯的store或以setData設定array data
每筆資料套用到itemTpl上,注意這裡接受的是XTemplate
1.String

itemTpl:'<p> {name}</p><p> {type}</p>'
2.String[]

itemTpl:[          
    '<p>{name}</p>',
    '<p>{type}</p>',
    '<hr>'            
].join('')
3.Ext.XTemplate

itemTpl:new Ext.XTemplate(          
    '<p>{name}</p>',
    '<p>{type}</p>',
    '<hr>'            
)
4.使用setData

var list={
    xtype:'list',
    itemId:'mylist',            
    itemTpl:new Ext.XTemplate(          
        '<p>{name}</p>',
        '<p>{type}</p>',
        '<hr>'            
    )
}
this.getComponent('mylist').setData([
    {
        name:'ozzy',
        type:'metal'
    },
    {
        name:'linda',
        type:'Rock'
    }
]);

四.使用注意事項
  1. 不要同時將html與tpl並用,否則html部份資料不會顯示
  2. 使用html,內容會被包覆在多層次的innerHtml class node內使用tpl則是將內容直接append進去不做任何節點包裝
  3. 若設定的資料為array資料,在tpl內使用for來處理迴圈list一定要用itemTpl不可使用tpl

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&amp;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();

2012年6月22日 星期五

Adobe Shadow: 好用的Mobile Web Debug工具


開發Mobile Web,Debug是一件很麻煩的事
Adobe Shadow提供了很方便的debug工具
可以把PC上Chrome瀏覽的畫面即時顯示在Mobile Device上
還可以讓PC Chrome 顯示Device上操作的相關訊息

簡單描述安裝程序

  1. 在PC上安裝Shadow 應用程式
  2. 在PC上的Chrome安裝 Shadow Extendtion
  3. 在Device(android,iphone ,ipod)安裝shadow app
  4. 在device上開啟app,連線pc,會得到一組序號
  5. 開啟pc上的chrome,執行shadow extension,會要你輸入device提供的序號
  6. 完成連線,Chrome上開的網即同時顯示在device上
  7. 在chrome shadow顯示的device<>按下去,會開啟debug console
  8. 選擇要debug的target,之後device上的動作,訊息都會顯示在pc上


下載網址 http://labs.adobe.com/downloads/shadow.html

2012年5月18日 星期五

Backbone.js Model 07︰Sample 使用Post執行Save and Delete

Backbone.js在與Server執行CRUD的動作,也就是Model的fetch,save,destroy等Method預設是以REST來與Server溝通,因為在REST裡update與delete是用到 HTTP的PUT與DELETE Method
如果你的Server不支援,只允許使用POST與GET
以下是處理方式

Client端
一.開啟設定使用emulateHTTP與emulateJSON
當開啟emulateHTTP時,Backbone會將原本應該用PUT與DELETE  Method與Server溝通,改成以POST Method來送資料,並另外多傳遞一個POST參數_method
1.執行model.save()
原本會以PUT HTTP Method與Server溝通
會變成以POST HTTP Method與Server溝通,
並自動加上一個_method='PUT'的參數送出

2.執行model.destroy()
原本會以DELETE HTTP Method與Server溝通
會變成以POST HTTP Method與Server溝通,
並自動加上一個_method='DELETE'的參數送出

3.開啟emulateJSON
會將要傳遞的model資料序列化後,以一個POST參數model傳遞給server
Backbone.emulateHTTP = true;
Backbone.emulateJSON = true;

二.model執行CRUD相關參數區別
1.model.sync 接收到method值為
"create","read","update","delete"
2.REST Server接收到的HTTP METHOD為
"POST","GET","PUT","DELETE"
3.非REST Server接收到的$_POST['_method']為
"POST","GET","PUT","DELETE"

三.改寫Model SYNC
所有與Server溝通的動作,都會去執行到Sync,當model或collection執行CRUD時,會先去檢查model或Collection內是否有定義sync,如果有就會執行內部的synce,若沒有就會去執行系統global的Backbone.sync

要連結Server的URL,系統會先去檢查Sync內的options.url是否有設定,如果有會採用這裡的url來與Server溝通,若沒有才會去檢查model或collection內的url設定值

所以要讓不同的執行動作連結不同的Server url,規則就必須是寫在sync內
以下是model 改寫sync對應CRUD提供不同的url sample
define(['_Backbone'], function(Backbone) {
    return Backbone.Model.extend({
        sync:function(method, model, options){      
            switch(method){
            case "create":
                options.url =API_Save;
                break;
            case "update":
                options.url = API_Update+"/"+this.id;
                break;
            case "delete":
                options.url = API_Delete+"/"+this.id;
                break;           
             }            
            return Backbone.sync(method, model, options);
        }
    })    
});


Server端(以PHP為例)
一.判斷Client端要執行的動作
$cmd=$_POST['_method'];
$id=$_GET['id']
switch($cmd){
    case "PUT":
        $this-&gt;_update($id);
        break;
    case "DELETE":
        $this-&gt;_delete($id);
        break;
    case "GET":
      $this-&gt;_read($id);
        break;
    case "POST":
      $this-&gt;_create($id);
        break;                    
}
二.取得model資料
$model=$_POST['model'];
if(ini_get("magic_quotes_gpc")=="1"){
    $model=stripslashes($model);
};        
$obj = json_decode($model);
就可以用$obj.prop..形式來讀取傳進來的json相關屬性了

2012年5月15日 星期二

PHP CodeIgniter 安裝與設定

一.環境設定
目標是建置一個可以多個Project共用的使用環境
1.下載CodeIgniter放置於Web目錄下
(或其他主機目錄均可),所有App Project都將共用裡面的system folder
2.Web目錄下建置,CI_Application目錄,用來放置要開發的所有App目錄
3.在CI_Application目錄下,建立新目錄(ex:MyApp1)
在目錄下建立.htaccess檔案,並Copy CodeIgniter下app目錄與index.php到此目錄下, 這樣一個目錄即代表一個App
檔案結構
/ci_application/MyApp1/.htaccess
/ci_application/MyApp1/index.php
/ci_application/MyApp1/app

二.Apache rewrite設定
1.開啟rewrite mod
ubuntu:
cd /etc/apache2/mode-enabled
touch rewrite.load
寫入 LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
window
開啟 conf/httpd.conf
LoadModule rewrite_module modules/mod_rewrite.so
2.http conf設定
ubuntu:
開啟 /ect/apache2/sites-avilable/default
window:
開啟 conf/httpd.conf
在相關的<directory>內</directory><br />
AllowOverride All(none都改成All)

三.App Project設定
1..htaccess設定
RewriteBase / 設定在這App內要作rewirte以哪個目錄當作這App根目錄

RewriteBase /ci_application/myapp1/
2.index.php設定
設定$system_path與$application_folder,設定的字串可以使用相對路徑寫法
例:目前的設定都是把application目錄放在Project下
web_root/ci_application/MyApp1/app
$application_folder='app'

system目錄統一放在CodeIgniter目錄下
web_root/codeIgniter/system
$system_path='../../codeIgniter/system'
3.app內的config.php設定
//設定這個APP對應到的網址
$config['base_url']    = 'http://192.168.2.104/ci_app/myApp1/';
//設定index_page為空白,就可以讓網址上看不到index.php(只看到路徑/ci_application/myApp1/)
$config['index_page'] = '';
4.app內的database.php設定
設定要使用的db連線相關資訊

2012年4月20日 星期五

SoundManager 延遲初始化

在使用JavaScript做音樂播放上
SoundManager是個很好的工具,可以偵測環境以Flash或HTML5做播放
不過在設計上有一個很大的問題是
當載入SoundManager的JS檔案
他就會立刻initial產生出一個window.soundManager物件
讓你可以用global方式使用window.soundManager做聲音的控制

有問題的是
在物件初始化完成之前
你必需要使用soundManager.url 設定要使用的swf檔案路徑

以官網上的sample來看,設定url的時間點都是在跟init的程序搶時間
除非你在網頁上以inline的方式寫入soundManager.url
否則如果這設定在init程序完成後才設定,那麼soundManager抓不到swf
而造成使用失敗

要如何禳soundManager可以延遲init,以保證soundManager可以正常運作
1.在載入soundManager.js前,先設定
window.SM2_DEFER = true;

2.在載入soundManager.js後
執行
window.soundManager = new SoundManager();    
soundManager.url = "swf/";
soundManager.beginDelayedInit();
這樣就可以保證可以安全運作了

2012年4月7日 星期六

以iScroll建構Mobile Web頁面

希望建制一個有header content footer的網頁,header與footer固定在上下
content可以scroll的頁面,scroll部份使用iScroll來處理
相關注意要項如下
一.網頁
 <div class="wrapper">  
      <div class='header'></div>  
      <div id='myContent' class="content">  
           <div class='scroller'><div class='itemContainer'></div></div>  
      </div>  
      <div class="footer"></div>  
 </div>  
要scroll的內容下需有一個唯一的子節點(div或ul都可),iScroll會對這個div做scroll
在這裡就是對content下的scroller這div
也就是說你在這下面塞的東西都會被scroll

二.CSS
設定一個有footer有header的頁面
1.架構
wrapper,content,footer,header,這四個主要架構要以
position:absolute來定位,而在z-index層次上
wrapper在最下層
content在中間層
footer,header在最上層
在這主要架構下的內部分層,就不需要用absolute來定位
2.尺寸大小
header與footer在高度上定好絕對的高度,寬度以100%設定來與wrapper保持同樣寬度
content因為可能會因為螢幕大小變化或旋轉螢幕而需要調整
這部份就需要靠JS動態改變高度
3.wrapper 整個頁面包裝
.wrapper{
  position:absolute;z-index:1;//以絕對位置設定當作最下層layer
  top:0;left:0;//設定貼在browser的最左上方
  margin:0;padding:0;
  width:300px;//可以用%設定
  height:300px;     
}
4.header 
.header{
  position:absolute;z-index:3;//設定在最上層
  top:0;left:0;//設定貼在wrapper的靠左上方
  margin:0;padding:0;
  width:100%;//設定與wrapper相同寬度
  height:50px;//設定header的絕對高度     
}
5.footer
.footer{
  position:absolute;z-index:3;//設定在最上層
  bottom:0px;left:0;//設定貼在wrapper的靠左下方
  margin:0;padding:0;
  width:100%;//設定與wrapper相同寬度
  height:50px;//設定header的絕對高度     
}
6.content
.content被設定到iscroll,重點是
.content要設定overflow:auto,高度則透過js來設定到達(wrapper-header-footer)高度
.content以下的container絕對不要設定高度,否則內容就無法scroll了
.content{
  position:absolute;z-index:2;//設定在中間層
  top:50px;//設定在header的下方,也就是設定header的高度
  left:0;
  margin:0;padding:0;
  width:100%;
  height:200px;//設定wrapper扣掉header與footer後的高度,這部份由js動態改變值
  overflow:auto;//設定內部的所有內容在超過的時候以scroll顯示
  >.scroller{
    width:100%;//注意千萬不要設定height,內容超過時才可以scroll
    >.itemContainer{
      width:100%;//注意千萬不要設定height,內容超過時才可以scroll
    }       
  }
}

三.JS
1.instance
要當作scroll的DOM container確定已經產生好才去產生iScroll
設定container要以id設定,不要用class
window.scroll=new iScroll('myContent',{
  hScrollBar:false,
  vScrollBar:true,
  hideScrollBar:false
})
2.refresh
在更新container內容,後需執行refresh動作,
且包在setTimeout內執行
setTimeout(function(){
  window.scroll.refresh();
},0)