慚愧,上一篇blog發表時間是12年8月份,現在已經13年2月份了。唉... 此處省略1w字。
半年有余,blog一直閑置了。但是閑置並不代表忘記。時不時還是會敲開cnblogs的域名胡亂逛逛。馬上年關了,公司里該回家的人基本不是准備回家就是在回家的路上。年前該忙的事情忙的差不多了,該做的項目也做的差不多了。順手記點東西吧。表示我並木有忘記這里 :)
既然是技術博,個人總結,感想之類的還是就免了。就算總結也要總結的跟技術沾沾邊不是 :)
【關於Web App】
咋們現今說的web app,現階段亦可簡要定義為OPOA,或者再詳細一點是經由 路由(hash)驅動的OPOA,單頁應用。開發這種類型的應用,需要關注的幾個點,大致可以歸結為以下幾個方面。
- hash驅動: 現在主流的方案都是 hashchange + history[pushState] 來做。每一個 #hash的變更對應一個 單頁應用 “子App”的加載和啟動。好的和強大的router機制就顯得尤為重要。將hash的匹配轉化為對應的js可執行方法,主流的web app 的框架基本都是此做法,通過hash匹配對應的function,此為“驅動”。
- 子路由和hash持久化:當然單頁應用復雜起來,除了會衍生出很多“子app”,可能在每個“子app”里面也需要更為細分的“路由驅動和持久”。比如一個“子app”里面有翻頁,或者富交互的彈層等... 所謂持久化,即為每一個“有意義”的url都能使頁面還原為預期的樣子,比如子路由里面帶頁碼,帶tabid,帶彈層顯示與否的flag。一旦有這種在交互設計中有意義的參數,實現上都應該記入持久化考慮的范疇(除非這個產品交互本身就不要求)。頁面完全按照url的要求而表現。
當然也可以用url之外的東西來完成持久化的功能,比如記入cookie或者localstorage來做。但既然你已經有了一套完善的router機制,為什么不用呢? - 數據異步化:web app和web page還有個較大的不同點在於 web page是server端直接吐頁面,異步數據可能也是頁面中局部的模塊在用。但是web app是整站,整個app都是異步數據接口在做。server端只負責從數據庫中挖數據做拼裝。數據parse,數據填模版都是前端的工作。大量的異步接口和數據必然導致異步編程體驗。改善異步編程體驗,這是一份重要的工作。這就需要你有一套好的Model機制。Backbone很多人喜歡用,除了它有我上面說的較為的完善router機制外,還在於它也把異步的數據請求體驗通過 message 改善了不少。
fetch或者Model.set的時候自動會觸發 ‘model.change’事件。其實對於消息訂閱機制稍微熟悉一點的高級開發者,這種消息機制完全可以自己實現,並且代碼量極少。關鍵在於你的思路有木有跟上。 - 模版前端化:上面說了數據異步化,既然數據都放到了前端的處理,模版自然也就放到了前端。從后端的模版慢慢發展到前端,逐漸也有了好多好多人的工作。有Less-Logic的,比如大名鼎鼎的mustache的js版本,或者mustache的改進版Handlebars等。為了針對js這種語言,后面又有了針對js的模版,Full-Logic的,大量的,每個公司自成一套的js模版,比如jQuery.tmpl, tmpl, ejs, micro template ... 以及各種以公司或者js基礎框架命名的js模版,這里就不提了。模版的優劣不在本文的討論范圍,這里要提的是在使用模版的時候盡量也要考慮到局部刷新的機制,再復雜的app都一個render,一個大模板,任何一小塊數據更新都整塊全部干掉重新填進去,顯然是不合適的。所以建議在模版划分的的時候也考慮到子模板的划分。(除非你的模版系統本身就支持局部刷新【chunk機制】)
- 事件代理:接上面,因為前端模版的出現,頁面上dom大多不是html頁面一開始被瀏覽器解析完就有的,而是后來通過獲取異步數據->拼接模版->innerHTML填到html對應容器里面的。正因為這種情況的出現。事件的綁定就要特別的小心了。好多開發不是很熟練的同學經常會犯的低級錯誤,說怎么我模版里面有這個dom,而且我通過inspector調試工具也確實找得到這個dom,但是怎么事件綁上去沒效果。這里就要小心檢查下是否你綁事件的時機是在render,也就是你拼接好的的dom str 填進頁面dom樹之前了。當頁面中都沒有這個dom,怎么可能綁事件有效果。用jq的同學又因為jq的容錯機制,導致dom其實沒有都沒有發現報錯而一頭霧水。
即使你確定在render之后再綁的事件,但是也不一定是好的策略,因為模版機制會讓你的容器里的html不斷的刷新。一旦dom刷新了,不但你之前綁的事件沒了,還容易引發內存泄漏各種問題。
所以這里delegate明顯是更舒服的方案。通過外圍的容器來代理容器里面的dom事件。方便且可以規避很多不必要的問題。
上面說了這幾個點,是我個人認為,開發web app需要着重注意的幾個點。把這幾個點都一一做好了,開發OPOA的web app自然也會變得容易起來。
【關於框架】
- 看了上面說的,好多同學應該都會說那我直接用backbone不就好了。它把上面幾點都做的還算不錯。而且易用性也蠻好,上手也快,backbone+underscore+jquery 快速開發OPOA應用蠻不錯的搭配。
- 但是我還是想說說可能更深層次的需求和其他的框架間的對比:
- 比如就backbone這種mvc式,它足夠輕量級,api也友好,搭配其他js基礎庫也方便,可是它的router配置機制似乎還是沒有期望中強大,至少簡單的和python這種后端腳本對比一下就發現。另外就是backbone並沒有提供“組件”機制。這也是國內外很多大公司迫切需要的東西。大公司都渴望沉淀,都希望在做項目的同時還可以順帶沉淀下各種組件,控件等。但是如果你用backbone,就會發現它並沒有提供 它的規范下的“組件”機制。 當然我們必須得承認人家在設計這個東西的時候“組件機制”可能本身就不在它的范疇。
所以,“組件”其實也是每個大公司都在嘗試深挖和沉淀的東西。可惜似乎沒有特別優秀的例子。 - 除了mvc老式框架。后來國內外(主要是國外)又衍生出了MOVE[model,operations,view,events], MVVM[model-view view-model] 等等各種適應不同場景的開發模式。MOVE算是MVC一個小進化版,Linkedin的一個工程師提出的,但似乎沒有好的清晰的實現版。有的實現看起來跟MVC並沒大出入。 MVVM我覺得 微軟一直在致力和嘗試的方向,從doNet到現在win8的開發模式中,都或多或少的可以看到MVVM的影子。尤其是win8的開發。使用過win8的js lib的同學應該都會有感覺,他的控件和模版的方式,以及data-bind, 和另一個目前主流的MVVM 框架knockout.js 都有不少相似的地方。 其實我是覺得knockout.js 是借鑒的 微軟的思路在做。:)
另外還有google的一個MVVM流派,那就是angularjs, 當然knockout和angular我都沒深入使用過,沒什么發言權。 - 但是就我個人觀點認為,mvvm的模式可能目前來看更適用於PC端的web app開發。mvvm的模式內耗太大了,而且像angularjs這樣通過自定義標簽來做二度parse和渲染的模式,在瀏覽器渲染引擎不夠給力的情況下,難免會存在組件渲染消耗高,甚至頁面組件“閃動”的情況。就PC端而言,我想這些還不是大問題,但是對於mobile端,我並不是很推薦。負荷有些重。
- 然而對於backbone應用在mobile端,我這里還要提一下,backbone 的 getHash 和內部 this.location的 對象緩存在 低版本android上[android 2.2, 2,3] 是有坑的,可能導致router失效。使用的同學在這種場景下需要特別注意!
【關於 Web For Mobile】
這半年我幾乎一直投入在Mobile端 web app 的開發上。有幾點可以和大家分享討論下。
- 首先,做mobile端的web app,順手的地方在於H5相關的新的特性基本上大體都可以隨手拿來用,不管是css3的樣式,排版,transition動畫等,基本上加上webkit前綴都可以放心拿來用。其他的特性,像什么localStorage,sessionStorage,history api,要用起來也是很方便。
- 但是不要高興的太早,mobile端蛋疼的可能不在於 features的支持上,而是在於客戶端版本和瀏覽器的多樣化上面。css咋們放心的用,放心的排版,基本出來的東西各個平台,各個版本基本都八九不離十。但是在交互行為的表現上,低版本的android 和 很多奇葩的第三方瀏覽器 詭異的坑有可能讓叫天不應,叫地不靈。
- 表現比較乖的ios 5+ 的原生safari 和 android 4.0+的原生瀏覽器我就不多說了。 重點說說不太乖的低版本的android和第三方瀏覽器的各種坑。隨便舉幾個例子:
- 針對於彈出層,這是最容易出坑的地方,比如一個特殊的場景,在一個浮層中,加入有一個list列表,並且通過事件代理,list中每個item都通過delegate綁定有點擊事件,假如列表很高,而彈層始終保持屏幕可是區域高。此時假如list的scroll采用overflow:auto原生滾動的話,除了低版本android不支持外,在高版本android中,靠近底部的list的最后一個item點擊可能會出現詭異bug,e.target獲取到的可能是遙遠位置的元素。
- 同理,由於android對於事件代理以及dom表現的“緩存”機制,當有類似“抽屜”效果這種簡單的展開,收起的效果時。假如使用overflow:auto原生的滾動,當展開抽屜-滾動-關閉抽屜或者展開別的抽屜的時候,再點擊可能出現詭異的bug。
- 所以建議還是自己寫scroller靠譜,既兼容低版本android又能規避一些未知bug
- 另外,關於android上input:focus時input不隨軟鍵盤升起而抬高的情況,建議嘗試 :focus{-webkit-tap-highlight-color:rgba(255, 255, 255, 0);-webkit-user-modify:read-write-plaintext-only;}
- 還有比如ios5極其以下版本使用 transition 針對input[display:block]進行變化的時候,會有極其明顯的殘影,建議有這種對input有動畫需求又有改變display屬性需求的時候,盡量采用 inline-block;
- 還有比如ios上使用transform的時候的閃屏問題可以嘗試使用
-webkit-transform-style: preserve-3d; -webkit-backface-visibility: hidden;
解決。 - 另外還有android上的touch事件穿透的問題,原生的瀏覽器基本上 e.preventDefault(); e.stopPropagation(); 結合一下可以解決大部分版本的瀏覽器。但是 UC for android 穿透依舊繼續...
- 另外再吐槽一下UC的極速模式,在腳本請求高並發的時候可能會讓你的腳本一個也down不下來。這種情況請使用 腳本loader的同學同時又有兼容UC瀏覽器需求的注意。
- 還有,“target=_blank”, "window.open" 這樣的嘗試新開窗口的東東 在低版本android上的uc 和qq瀏覽器上 都將失效。
- ......
- 總之一句話,想在mobile端做到瀏覽器全兼容,體驗全一致,同樣是件極其蛋疼的事。
- 另外,對於mobile端,尤其是2G網絡的情況,http請求更多的時間可能是花在DNS連接和握手上面,所以這種情況下的 資源合並,和http鏈接數的減少就顯得更為重要。這對於使用loader或者類似 seajs 這樣的默認按 app package 打包壓縮的同學,在優化的時候可能可以考慮下更進一步的資源combo, 有可能對你的項目性能提升會有幫助。
- 此外,我想說的針對mobile端,還可以探索的領域還有不少,比如一個很重磅的東東,canvas,在目前mobile端的web 上,幾乎見不到任何實際應用的例子,但是我覺得其實mobile端也是可以開始有空間給canvas發揮了。現在2000塊的android機 的cpu 跑 canvas的demo,300粒子的系統跑到50fps沒有什么壓力。關鍵是應用場景,我覺得未來canvas在移動端的嘗試可以從替代一些簡單的gif,或者flash動畫開始。甚至可以做runtime的 資源分離 和組合的系統, 這種東西對於電商的“牛皮癬”需求是可以形成新的解決方案的。
【關於響應式】
這一兩年這個概念開始在互聯網圈子里面慢慢熱起來。起因也是由於多終端的普及,同時降低開發維護成本。我同樣一套代碼和樣式,可以兼容不同大小,不同分辨率的終端,不用為了不同的分辨率重新設計一套系統,這種降低成本的事,誰不願意做?
關於響應式,我想說的不多,
- 一個是css中注意 @media query 這種東西的使用,在mobile端極其有用。在使用 @media 的同時,也不要忘了 background-size 這樣的東西,在某些特殊的時候,會給你意外的驚喜。
- 另外一個就是 js中 resize事件的合理使用。 我並不建議在resize 事件里面 為了適配 不同的大小 大幅篇章的直接操作一大片dom的樣式。我估計這樣做的同學自己也會被繞暈。在dom樹外圍容器上 加上 class 的命名空間, resize 適配的時候只需要將 這個className 適配為預期的className, 其他的布局改變 還是放在css里 這個對應 class 命名空間下面來做。會為你省事很多,也提升性能不少。
不知不覺,將近3個小時就過去了... 打了不少字。大部分也算自己這半年來的心得和感知吧。
打了這么多字手也累了,總之還是希望勉勵自己一下,blog還是希望繼續寫下去,“
勿以善小而不為,不以惡小而為之
”
PS:instagram昨天好像出 web 版了,這算是道內的新消息,總體來說,instagram這個產品,我挺喜歡的。