基于 Vue.js 的后台单页应用管理系统的研究与实现
摘 要
通过研究Vue.js、路由、全局状态、axios等技术,实现后台单页应用管理系统。对actions进行封装,并在配置文件中定义好相关请求信息,即可实现带后台API请求的action操作,极大程度减少系统代码量,并保证系统的统一性、健壮性。前端页面根据菜单策略控制页面文件的入口,根据页面权限控制策略进行按钮级别权限校验。
关键词:Vue.js;MVVM;单页应用;权限管理
引言
为了满足日益复杂、多样的Web App需求,越来越多的原本后端处理的业务逻辑开始转移到前端来处理。Vue.JS就是这样一套构建用户界面的渐进式框架,方便大部分后端逻辑移植到前端去实现。Vue.JS采用自底向上增量开发的设计,其核心库只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当Vue.JS与单文件组件及其Vue.JS生态系统支持的库结合使用时,也完全能够为复杂的单页应用程序提供驱动。由此,采用Vue.JS进行后台管理系统的前端设计工作,一定程度减轻前后端开发人员开发难度。
系统关键组件选型
本系统前端工程基于流程简化、低成本、快速开发、高性能等需求,主要选用到 Vue.JS、vue-router、vuex、axios等关键组件。
Vue.JS是整个前端工程的基础视图层框架,主要解决前端数据绑定的问题。传统的前端开发,主要基于jQuery通过各种复杂的选择器来操作DOM。同时,通过AJAX跟服务器请求数据,前端代码一层层解析JSON,将JSON某个层级的数据赋给相应的DOM操作,还要进行请求的异常处理,数据不但操作繁琐复杂且易出现未知错误。而通过Vue.JS的响应式双向绑定数据,实时反映数据的真实变化并映射到目标虚拟DOM上,避免前端页面开发中DOM选择器繁杂的操作,简化Web前端开发流程和降低开放难度,提升前端开发效率,降低开发成本和周期。
vue-router是Vue.JS官方发布的一款路由插件,和Vue.JS是深度集成的,适合用于构建单页面应用。传统的页面应用,是用一些超链接来实现页面切换和跳转的。而在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。通过router-view来动态挂载页面组件,并最终渲染成页面。另外,HTML5里引入了新的 API,history.pushState和 history.replaceState,可以通过这个新的接口做到无刷新访问页面的同时改变页面URL,这让Vue.JS能够动态调整页面路径,方便页面切换,提高了用户体验。
vuex是Vue.JS官方依照Flux实现的一套全局状态管理方案,并被集成到vue-devtools,无需配置即可在浏览器中实现时光旅行式调试。当开发单页应用时,我们通常会把状态储存在组件的内部,每一个组件都拥有其自身的状态管理,但是在整个应用层面上看,很多公共的状态是却是分散在各个页面中。同时,我们经常会需要把状态的一部分共享给多个组件。一个常见的解决方案是使用事件系统来让一个组件把一些状态“告知”到其他组件中,来让相应的组件去响应变化。但是这种模式的问题在于,大型组件树中的事件流会很快变得非常繁杂,并且调用时很难去找出究竟哪里出错,事件的冒泡也很有可能导致整个应用的资源消耗非常大。应用越来越大,页面文件数也越来越多,多个状态分散的跨越在许多组件和交互中,其复杂度也经常逐渐增长。使用vuex将状态放入一个全局的实例中,做到各个组件同步响应,减少系统状态复杂度。但是在使用全局状态管理时,我们还需要对组件的组件本地状态(componentlocalstate)和应用层级状态(application levelstate)进行区分,避免出现组件本地状态放到应用级状态去管理。应用级的状态不属于任何特定的组件,但每一个组件仍然可以监视其变化从而响应式地更新DOM。通过vue-router我们解决了页面切换问题,通过vuex我们解决了全局状态共享管理的问题,但是所有应用的基础在于数据。传统数据请求,主要利用jQuery封装的AJAX请求来实现。在处理异步问题时,一般采用的是callback回调的方式。callback回调存在一个很严重的金字塔问题——大量的回调函数慢慢向右侧屏幕延伸的一种状态。通过采用含Promise特性的组件来进AJAX请求,使得我们可以用同步的代码形式实现异步的请求操作。axios就是这样一个基于Promise用于浏览器和nodejs的HTTP客户端,其可以从浏览器中创建XMLHttpRequest,支持Promise API,同时方便实现请求过程中的中间件操作,例如权限校验。
整个前端工程总结下来,主要采用vue作为基础视图层框架,利用vue-router完成前端页面路由的跳转及各类访问拦截功能,采用axios作为HTTP请求库,同时利用vuex负责前端的全局状态管理,采用iView作为界面基础组件库。
Vue.js的运行原理
在介绍Vue.js运行原理之前,先要介绍几个概念。Observer本质是一个数据监听器,不言而喻它是起到一个监听的作用,对于数据对象中的所有属性,它都能够对其监听,告知订阅者哪些属性发生了变化和发生了哪些变化。对于指令解析器Compile,它是对Vue.js中的指令进行扫描,并对扫描后的指令进行解析编译。Watcher相当于一个协调者,它主要的作用是在Observer和Compile之间建立起连接,它不但能够接收来自Observer的属性变化通知,而且从中起到一个调度的作用,并执行指令绑定的相应的回调函数,从而更新视图。
在Vue创建一个对象时,首先会为这个对象进行一个初始化的过程。在初始化的过程中,Observer会一直对这个对象所有的属性进行监听,同时Compile会扫描Web页面中的指令,对扫描后的指令进行编译,并会初始化视图。而Watcher会在Dep中添加一个订阅者。当系统一旦运行起来,Observer监听器就会获取属性变化并通知Dep,在Dep中会查找与该属性对象对应的订阅者,并向添加该订阅者的Watcher发送变化通知,从而对视图进行相应的更新。
Vue.js与React.js的对比
React.js最早的时候是Facebook公司的自己做的一个项目, 当时的前端框架都是基于传统的MVC模式,但是传统的MVC却很难满足Facebook公司当时的要求。因为当时项目是一个很庞大的项目,包含非常复杂的逻辑结构和相当多的程序代码,所以便诞生了React.js。首先Vue.js与React.js是有很多相似之处:
1.使用 Virtual DOM。
2.提供了响应式(Reactive)和组件化(Composable)的视图组件。
3.将注意力集中保持在核心库,伴随于此,有配套的路由和负责处理全局状态管理的库。
本文侧重比较Vue.js与React.js不同之处,并通过比较体现Vue.js的优势所在,所以这里不再对相似之处进行赘述。
对于Vue.js与React.js不同之处笔者通过一个小例子进行对比。当我们对用户界面进行渲染时候,为了降低Dom的操作React和Vue都是通过Virtual Dom抽象层来实现这一要求,对于必要的Dom 操作以外,必须要减少另外功能的消耗,比如一些页面运算等等。这就是 Vue 和 React 存在的不同之处。为了证明这点,我们建立了一个简单的参照项目,它负责渲染 10000个列表项 100 次。
为了客观的得到实验结果,笔者对实验项目进行了二十次的运行,并获取各自运行中产生的最好结果。通过运行结果可以明显的看出未经优化的 Vue 相比未经优化的 React 要快的多。由于 Vue 改进过渲染性能,甚至全面优化过的 React 通常也会慢于开箱即用的 Vue。
渲染性能只有Vue的强大性能之一,相比其他前端库Vue还具很多特点,首先Vue.js是一个轻量级的前端库,上手简单,对于新手来说不需要太多的时间就可以学会。对于DOM的更新,Vue使用了异步批量处理方式,所以会非常快速,同时它还可以将每个组件进行一系列组合,这样对于程序的解耦性和重用性都得到了大大提高。
架构设计
整个后台单页应用管理 系统分为两个工程:前端工程、后端工程,以API接口形式联合前后端。前端工程中,以components作为独立页面组件的存放目录,使用pages作为系统页面的存放目录,所有涉及全局状态管理的代码存放在store目录,涉及路由配置的代码存放在router目录下,通用的配置文件存放在common目录。通常,在进行store设计时,会将所有的action集中在action.js文件中,其中包含通过axios进行后台api请求的代码。在进行后台单页应用系统开发的时候,会频繁跟后台进行数据沟通,故考虑将action分成两种类型,一种是不带后台API请求的,只是单纯进行前端操作的,另外一直则是包含后台API请求,跟后台进行数据沟通。根据以往经验,大概2/3的action会涉及后台API请求,故需要通过某种形式来减少重复的请求代码。经过对上述问题的思考,可以通过以下方式来减少系统的代码量,同时保证请求统一性,尤其是请求异常的统一性处理。
另外,在进行前端系统设计的时候,还需考虑整个系统的权限问题。在后台应用中,主要是在中间件中根据RBAC来鉴别用户权限。在前端页面中,主要分以下三个层面进行用户权限的控制:第一层,主要是对用户入口的控制,表现为:根据用户角色来获取用户所能访问的菜单列表。第二层,主要是对用户访问页面的时候,进行权限鉴别。在router的全局钩子中,根据用户角色的权限,来鉴别用户是否拥有访问该页面的权限,如果有权限,则next(),否则,直接重定向用户到401页面。第三层,当用户只有访问页面权限,但没有进行操作权限时,通过封装的hasPermission方法动态展示或隐藏相关操作入口,也可以根据实际请求展示或隐藏相关数据列。
部署实现
通过前后端分离,来保证前后端发布的独立性。针对前端工程,利用webpack打包来生成生成环境下的前端代码。针对后端工程,则需根据特定的开发环境,打包相应的生产环境应用。当进行前后端分离发布,也经常会遇到跨域的问题,为减少代码层面的修改动作,可利用Nginx进行反向代理,将两个工程的放到一个域名下去部署,从而解决跨域问题。以下是以PHP应用为样例的Nginx配置文件,其主要思想是将对前端页面的请求反向代理到前端静态页面,由前端vue-router进行页面路由控制;
结语
本文主要从组件的选型、系统结构设计以及部署实现三个方面,详细描述基于Vue.JS进行后台单页应用系统的设计工作。对相关组件的封装,并以配置的形式主导功能的开发,在一定程度上减少后台系统的前端开发工作量。利用Vue.JS的双向绑定特性,高效地将数据反映到页面模型上,同时Vue.JS更高效地处理页面DOM操作,提升后台应用的性能。