惭愧,上一篇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这个产品,我挺喜欢的。