有一段都在重构之前文章《我和我的广告前端代码(三):一次重来的机会,必要的技术选型》中提到的广告前台展示项目,原有的基于页面的请求,改成了单广告位请求在这个过程中经历了好几次架构变更以及项目刹车。回过头来看看,感觉收获很大的。才刚刚把前台展示弄完,又开始了新的挑战——后台投放。
其实原来也是有投放系统的,自从我去年接手的时候就有了一个庞大的后台投放系统。这个系统的后台写的还是很不错的,但是由于当时前端团队人员较少,整个系统的页面就变成了,前端做个静态页,后端套模板的实现方式了。由于后期由后端同事孤立无援的完成,导致这页系统的前端页面并没有想象中的好维护。先说明一下,并不是说后端做出来的页面不好,只是说最终还是要交给前端来维护,为了方便以后的维护,我们必须要做些什么。为此我一直在思考这个问题,恰逢后台系统有了一个新需求,不说业务,主要是要添加一个页面来专门处理一些业务,但是有和别的业务没什么耦合,简单来说,就是一个完全新的,随便玩儿的空白页,风险也比较小。那么这是一个机会来尝试着用一些适合处理后台系统页面的技术来开发。下面我来介绍一下吧:
为什么不延续原有的,直接迭代出一个页面?
其实如果我们不改变原有的,利用原有的页面能不能拼装出一个页面,再加上业务逻辑,直接上线万事大吉呢?答案肯定是可以的,虽然完成了需求但是这样做的结果会让不好维护的页面变的越来越多。那么原有的页面有哪些问题呢:
1、模板没有按组件为单元切割成片段,好多页面上用到同一个结构,采用的方式拷贝这一段代码到不同的页面。问题也比较明显大量重复的代码,修改的成本比较高。
2、js引用没有模块化,完全依赖加载顺序,大量内联js。由于上面模板的重复拷贝,导致js重复拷贝,或者为了使用别的页面中的某一个功能,却引用了那个js文件。
3、css混乱,预编译、没有分模块,式样相互覆盖。
4、数据驱动的页面,利用jquery大量的修改DOM,大量数据写在DOM上,js中数据走向不连贯,如果不运行调式一番,很难弄清楚数据逻辑。
5、大量的第三方依赖,为了初始化组件,全部都在页面的一开始就运行了,很难划分调用周期。
6、每次局部数据的变动,依赖的是form提交儿造成的页面刷新。这种整个页面的渲染,应由ajax + 局部渲染来完成。ajax仅仅是获取局部变化的数据,而刷新请求返回的却是整个文档(不仅仅是数据,还有后台渲染后的html字符串),从速度上来说ajax又划算的地方,但是ajax渲染也有不好的地方,比如一旦业务模板改动,就要同时修改维护*.tpl(或*.jsp)和js中的前端模板 两套模板。
优化方案:
考虑到新需求是新增页面,而不是对老页面迭代,使用新技术方案的“推翻成本”并不高。而且新做页面从排期上,可以争取到的时间也会比较充足,考虑到新技术方案带来的高效率和调研摸索导致的时间延长,综合来看刚好可以完成开发。B端的页面也不用考虑IE的兼容性,这为使用现有主流MVVM框架提供了便利条件。接下来我们看看如何解决这些问题:
首先这是一个B端系统的页面,由于大量的数据交互、DOM修改和少量的动画特效,很容易我们可以想到使用某个MVVM的框架来实现需求,利用MVVM框架一方面可以处理复杂的DOM操作带来的性能瓶颈,另一方面是我比较懒惰,想借用一些框架中现成的组件化思想来分割页面实现模块化。最终考虑到框架的可维护性和框架的轻便程度我最终考虑使用Vue来进行开发,从另一方面来说,主要是angular1.x与2 的不兼容,而我对2也不是很熟悉;react和vue方面同为组件化思想的框架,但vue比较小巧,中文文档也比较丰富。
我们一起来看看针对上面的几个问题,vue.js框架是怎么解决的。
1、模板分割的问题:vue采用的是组件化的编程思想,我将页面划分为多个独立的组件,分别封装到*.vue文件中。在官方文档中也对组件间的通信有丰富的解决方案。独立管理组件各自的生存周期和内部的数据到模板的渲染。实现有数据驱动的自动渲染,将html的碎片封装在js(vue)模块中。
2、关于js的模块,按需加载、循环引用的问题,我使用的是webpack 下ES6的方式,commonJS来管理js模块和vue模块
3、css我本想用less来处理,后来想的是用*.vue中对style的处理,最后合成css 的方式来尝个鲜。
4、处理大量数据驱动模板的问题,vue的虚拟DOM方式通过计算diff后再操作DOM,会大幅提高页面性能。
5、大量的第三方依赖:通过webpack来实现管理,控制三方库的调用时机。
6、局部渲染的问题:不编写后端模板,只维护前端模板并放在组件模块的内部,ajax返回的数据直接驱动模板变化HTML,不用重新请求整个页面,js局部渲染的工作也不用亲自操作DOM,而是交给数据-模板的双向绑定。
怎么做的?
这次我相当于直接在一个白页上开发,当然还是要借用公共头和公共尾和一些通用的导航。剩下的主题部分,就是我们施展拳脚的舞台了。在阅读vue文档的时候发现,其实vue官方提供了一个脚手架,如果你曾经用过Yeomen或者类似工具的同学,应该不会陌生,没错,vue的开发团队为我们提供了vue-cli来方便我们创建一个vue的项目,官方出品,用着也放心啊。通过创建是加入不同的参数,创建的时候回答一些问题,你就会得到一个基本版的vue项目。相比Browserify我对webpack更熟悉一些,所以我选用的是webpack。具体的方法传送门。从生成的package.json 来看(下图),主要有一下这些:ES6、浏览器自动刷新、式样预编译、js静态检查、node服务、webpack、自动化测试以及断言库、vue等等。目录结构如下图:
这套架构下有一个亮点,就是es6的编译速度,我们常用的gulp babel编译速度比较慢。而这套框架中预设的编译方式 npm script 控制一个后台的服务,只要有文件修改,就自动编译输出到前台页面。
具体的业务实现就不说了,我在这里简单说一下我在这次的开发中遇到的问题和感受到vue强大的地方吧以及一些注意事项吧:
1、web conpontents 思想:vue中将组件化的思想融入到方方面面,甚至定义了一种封装每个组件的文件格式—— *.vue 文件。每个*.vue文件都由三部分组成:template、 script、 style 分别用来控制 模板、 js逻辑和式样。其中template使用的是vue的双向绑定的模板引擎;script中使用ES6的语法编写,控制这个组件的数据绑定以及相关的回调函数;style中是这个组件的式样,注意具有scoped属性的样式只会应用到当前元素和其子元素。
使用这套架构我们可以比较轻松的以文件为单位来划分组件模块。每一个模块有自己的js和css,这样可以在复用模块的时候,引入最少的代码。
2、es6快速编译:这一点不是vue带来的,而是vue-cli带来的。使用过babel的同学一般都抱怨过编译速度慢的问题,在使用过vue-cli中的编译后我发现是我原来的配制方法不好,vue-cli的方案是并不生成实体文件,而是在内存中不断编译,通过node服务打到前台页面中。虽然最后build的时候和原来一样慢,但是在调试的时候很快基本上是实时,而且即使你浏览器打了断点,但是新的编译结果也能反映到当前浏览器中(即使不刷新页面或者说他会判断是否改动的呈现是需要刷新页面的)。毕竟build只是最后一下。
3、既然提到了build ,需要注意一点:默认的build脚本中,对于生成的静态文件后面是带hash的,如果你不想要,可以在将build/webpack.prod.conf.js文件中webpack配置中的output中的“[chunkhash]”去掉即可,如下图:
4、npm script:过去我都一直使用gulp来管理工程,但是这个vue-cli并没有使用gulp,其实也可以理解vue官方出品怎么好依赖别人的工具。看到package.json文件的时候,我发现vue-cli使用的是npm script如下图。
我仔细查了一下,原来npm script已经被广泛使用在各大js库和框架中,好处在于npm的包要比gulp的插件数量多出好几倍、npm包的更新速度比gulp插件的更新速度快(以eslint为例先有npm包,后来才会有团队更新gulp-eslint)。只是我们用gulp用的太顺了。
5、父子组件:既然说到组件的划分,一旦颗粒度小,就需要组合一些组件实现新的组件,那么就免不了父子组件的数据通信,我采用的方式是子对父用event、父对子使用props、子与子就先event在props。
6、计算属性:这个是我个人比较喜欢的vue的功能,有时候我们需要对数据适配,但计算量又不大,有要求频繁计算,就可用vue的计算属性“computed”来返回想要的值。
7、静态检查:vue-cli配置的工程中在dev命令下会有强大的静态检查功能,会直接输出到浏览器中,指出那个文件的哪一行,有什么错误,该怎么改。就感觉是有一个大神在旁边看着我编程,稍微走偏一步,就会马上纠正。可以屏蔽好多语法错误。
8、局部渲染快:这应该是vue这一类框架都有的一个特点,就是通过计算数据变化在DOM修改层面上最小的diff,来渲染html。毕竟渲染局部所需要的数据总是小于等个页面大文档的,提交后,页面刷新的体验也不好。
总结:
这次vue开发的体验很是奇妙,一方面感受到vue的强大和合理,另一方面可以体会到vue-cli的规范和严谨。由于这次开发并没有覆盖太多vue的重要特性,所以既然我已经被圈粉了,vue的研究还要继续。