Vue全家桶实践项目总结(推荐)


Posted in Javascript onNovember 04, 2017

从前端的角度看,Vue可以说是目前最理想的前端MVVM框架,一切为界面服务,上手难度低,本文就将记录使用Vue全家桶(Vue+Vue-router+Vuex)重构一个jQuery+template项目的过程,以及期间的收获。

入门

Vue的官方文档就是学习Vue的最佳教程,没有之一,可能因为框架作者是设计出身,没有后端背景,因此各种抽象概念在Vue里都得以用最容易理解的方式被恰到好处的阐述,这里只简单介绍Vue、Vue-router、Vuex的概念,要全面学习建议去官方文档。

Vue

Vue的核心功能是双向绑定,可以自动实现界面驱动数据变化和数据驱动界面变化,这能极大降低前端富交互应用的开发成本。同类框架不止Vue一个,但Vue的实现借助ES5原生特性,在性能方面有一定优势。

Vue-router

Vue-router是官方路由,用来组织url和组件间的映射关系,并自动将url的变化响应到组件中去,使开发者只需将关注点放在组件开发上,路由帮你解决相关的琐碎问题。

Vuex

Vuex提供一种集中式的数据管理模式,用以应对数据流向复杂的情况,比如多个组件共用数据却各自为营,可能导致该同步的数据没有同步,或者由于js中Object对象的钩子在内存里指向同一实例,导致一旦操作原数据就会污染到其他组件,这时就需要一套更有条理的数据操作模式,那就是Vuex。

技术选型

跟jQuery对比

在了解了Vue的基本概念之后,肯定会不自觉的拿他们跟jQuery技术栈做对比,想知道这些东西对我的业务是否真的有必要。

首先MVVM解决的问题能不能用jQuery解决?答案是肯定的,还记得最初做表单提交时用jQuery从一个一个的input里取值吗?这就是界面驱动数据;如果做过任何异步交互功能的话,应该都有过用jQuery将Ajax数据填充到界面中各个元素里的经验,这就是数据驱动界面。虽然能做,但有点繁琐,即便用上表单验证插件和前端模板引擎,也仍然需要在各个运行节点手动调用验证方法和渲染方法,做个网站页面还好,可当需求复杂到一定程度时,这将是很大的负担。

然后是路由,路由的本质是通过操作url实现界面切换和界面保持,单页面应用必备,这个其实跟技术栈没关系,只要产生了路由需求,即使是基于jQuery的项目也不过是再造了一个路由而已,只不过jQuery时代很少做单页面应用。

Vuex完全是基于双向绑定延伸出来的东西,相当于在数据和组件之间加了一个经纪人,组件不能直接操作数据,只能像经纪人提交操作需求,由经纪人去实施操作,以此解决人多手杂造成的各种不可预料的问题,并且数据被从应用中挪了出去,专门建立了一个Store,这样就杜绝了组件之间数据污染的问题。jQuery应该说不太会有这个需求,因为jQuery完全是手动操作数据,根本没有意料之外的情况。

适用场景

经过跟jQuery的对比之后,Vue的适用场景就很明显了,从开发角度讲交互越复杂的项目越适合,单页面最适合,内容类网站最不适合,如果网站中个别页面有需求也可以局部使用,例如购物车页面。

当然,这一切都要建立在不兼容IE8的前提下,对于这一点我有点疑惑,因为见到有些2C的站点都在使用Vue,这些前端er是怎么把老板忽悠瘸的?

项目分析

项目背景

这次重构的项目是为上一家公司开发的前端组件管理系统,选择重构这个项目是因为对需求比较熟悉,这是一个典型的单页面应用,而且复杂度适中,比较适合用作上手练习。

项目背景是外包类建站公司里,设计环节沉淀了大量可复用组件,设计师往往只需要微调组件就拼凑出页面,交付给前端,理论上这些组件在前端也可以复用,但实际上前端每次都要重新实现整个页面,浪费很多人力。

功能需求

这个项目的思路是,将所有组件开发出来,统一录入到一个平台上管理,设计师可以到平台上挑选组件,并实时预览和调整组件,整个过程所见即所得,平台会将调整结果生成一串代码,只要将代码交给前端,就可以用这串代码在平台上重现设计师修改后的组件,并能一键复制组件的html/css/js代码,快速应用到项目中去,使组件部分的前端开发成本接近于零。平台需要实现以下几个功能:

  1. 管理组件,支持分类、搜索、排序
  2. 展示组件,支持组件在线预览/编辑
  3. 组件交接,支持生成组件代码和基于代码重现组件
  4. 使用统计,支持统计组件的使用情况,便于进一步优化组件

功能分析

第一版是用jQuery+template实现的,这个技术栈太灵活了,优点是什么需求都好做,缺点是怎么做都行,不利于理清思路,往往伴随着边做边改。

组件被统一放在一个widgets/文件夹里,被称作组件库,因为是纯前端项目没有文件操作能力,因此组件的读取依赖一个静态json文件,这个文件充当组件库的目录,其中包括组件分类、标签、名称、日期等所有信息,数据结构大概是这样:

[{
 "title": "导航类",
 "list": [{
 "widget": "bread-1",
 "title": "图标面包屑",
 "tag": "面包屑/图标",
 "author": "UI",
 "date": "2015-06-04"
 }, 
 ...]
},
...]

组件在组件库中以栏目/编号二级文件夹的形式存放,同时约定用存放目录作为组件代号,例如组件bread-1意味着该组件存放地址是widgets/bread/1/文件夹。

当然组件的内部文件结构也必须约定下来,如下:

widgets
  |-bread
    |-1
      |-album.jpg   //缩略图
      |-config.json  //配置文件
      |-script.js   //脚本模板
      |-style.css   //样式模板
      `-temp.htm   //界面模板

有了这些约定,程序就可以通过目录文件得到所有组件的信息,组件的获取、展示、检索也就可以实现了。

组件里最关键的是config.json文件,这里面包含该组件的可配置项及其默认值,平台在展示组件时会读取这个配置文件,根据配置信息生成配置面板,这里面可以定义组件界面、样式、脚本中的所有变量,配置文件大概长这样:

{
 "cssConfig": {
 "fontSize": {
  "name": "字号",
  "value": "12px",
  "type": "text"
 },
 ...
 },
 "jsConfig": {
    ...
 },
 "showConfig": {
 "viewWidth": {
  "name": "栅格宽度",
  "value": 12,
  "type": "number"
 },
 ...
 }
}

配置文件里的cssConfig、showConfig、jsConfig三个分支,就是组件中所有可以修改的变量集合,想将这些变量应用到组件上,需要借助前端模板引擎,所以组件的三大件在开发的时候是用模板语法写的,经过模板引擎的解析,就能得到配置后的实际html/css/js内容,例如样式模板大概是这样的:

.widget-bread-1 {
  font-size: ${fontSize.value}; 
  color: ${textColor.value}; 
}
.widget-bread-1 a { 
  color: ${textColor.value};
}
.widget-bread-1 a:hover{
  color:${hoverColor.value};
}
.widget-bread-1 .ion { 
  font-size: ${iconSize.value}; 
  margin: 0 ${iconMargin.value};
}

在得到组件实际代码后,只要将结果插入页面中并适时更新就行了,其中HTML和css可以直接替换文本内容,js因为是模块化引入的,只替换模块内容不会重载模块,必须将整个模块重命名后进行整体替换,因此js模块的名称是随机的。

这里会有一个问题,有的组件需要在页面里多次使用,那么这个组件的js选择器就会发生冲突,这个问题的解决正好可以借助js模块的那个随机名称,我们约定在组件开发中id作为保留变量,由平台自动赋值一个随机字符串,这个字符串在组件实例内部相同,多次调用则不同,这样只要将${id}作为组件父节点的id或class,就解决了选择器冲突问题,同时也可以作为组件的css命名空间,使可能发生的css命名冲突也解决于无形。

以上是项目核心功能。

此外还用localStorage作为存储方式实现了单机版的数据统计,可以收集当前浏览器的组件使用记录,以及每个使用时的配置情况,这里主要是对本地存储的操作,但是项目自身的开发也用到了前端模板,加上组件的模板,都会在第一次加载后用localStorage缓存起来,这些内容的缓存策略不同,用户数据应该是永久存储,项目模板应该可以手动更新,组件模板需要视情况而定,存储的内容多了就需要清理,清理的时候一条一条的去删除就不现实了,全部删除可能误伤其他应用的存储,这里的做法是将localStorage操作封装,存储方法会在在key前加上一个特殊前缀,删除时只要遍历本地存储的key并且判断是否匹配前缀就知道是否是应用内的存储了,对应的取值方法也要逆向的先给key加上前缀再去取值。

另外localStorage是只支持字符串存取的,为了方便我们存取对象类型,封装方法还支持自动转换,但这个转换还不能是盲目的遇到对象就转字符,取值的时候匹配到可以转对象就自动转了对象,因为有时候用户可能真的就存了一个对象字符串进去,取出的时候也希望原样拿回来,要解决这个问题需要做一个小hack,当存储方法检测到值为对象时,会转成字符串然后在前面拼上一个标识字符串,取值方法只有在检测到这个标识后才会将后面的字符串还原成对象,这种方式虽然可以满足需求,但不是很保险,因为这个前缀是固定的,理论上总是有可能遇到中奖的,不知道这个问题还有没有其他的更优解。

项目的主要功能点就是这些。

重构

一次重构

第一次重构只用了Vue,重构过程中首先体会到的是各种便捷,本来要调用模板引擎做的事框架顺便就做了,本来要在js里绑定事件现在模板里直接可以绑定,还有其他各种语法糖。

当然,最重要的还是双向绑定,基于双向绑定可以让界面和数据自动的关联起来,让人感觉程序具有了一定的自主能动性,但为了让这种自主性正常运转,开发者必须事先规划好每一步路,这相对jQuery来说就会显得不那么自由。拿搬砖头举例,jQuery好比一个特别灵活的起重机,可以举重若轻,可以花式搬砖;Vue则像一个万能遥控器,你告诉他你要把砖头从某地搬到某地,期间发生什么情况要如何处理,按动按钮就可以自动搬砖了。

两种方式各有优劣,起重机开的好可以很灵活,路上遇到坑容易躲避,缺点是你要一趟一趟的开它;按钮可以一次编程自动运行,缺点是你必须事先把路上的坑实地考察好,把别的车全部调度好,所有的情况说清楚,否则就会翻车或撞车,从jQuery转到Vue一定会感觉到这种束缚感,逼的你必须”谋而后动”,不能先上车再说。

重构期间很大一部分工作就是建立Vue实例,将散布在js各个角落的数据收集到data中去,将操作数据的过程一点一点的集中到methods中去,将数据的筛选过程集中到computed中去,这整个过程可以清晰的回顾每一个实现细节,反思每一个实现方式是不是合理,其实也就是将原来开起重机的过程归纳成一个一个的遥控器按钮,当全部归纳完成后,Vue示例也就变成了最终我们的项目,能够自动运行。

经过重构,依托Vue的各种功能使逻辑部分的代码量减少了,除此之外对项目本身来说并没有什么改进,因为没有路由所以刷新页面状态丢失问题仍然存在;因为没有使用Vuex还遇到一个数据污染的坑,只能用深拷贝解决;并且基于组件的开发模式,让代码组织更零碎了,这些问题都需要二次重构。

二次重构

二次重构目标是完善路由、Vuex、代码组织、野狗云后端。

虽然有了第一次重构的经验,但二次重构一开始还是有点茫然,路由和Vuex应该先上哪一个?想了想,路由做的事是”拆”,Vuex做的事是”改”,感觉改完再拆的工作量会小一点,所以先上Vuex。

Vuex的概念凭空理解有点抽象,一旦用上却觉得的得心应手,而且这个东西不像路由,几乎不需要区分场景都可以用,引入Vuex后数据污染的问题自然就解决了,而且Vuex带来的 action => mutation => store 流程一旦接受了真的会让事情变简单,引入Vuex的过程基本就是将data转移到store,将数据操作分散到actions,getters,mutations中去,同时很多同步数据操作都不需要了,从而使代码量又减少了一些。

之后开始引入路由,一开始拿不准应该怎么划分视图,大的视图肯定是登录、注册、主界面,问题是主界面需不需要再细分,理论上可以分的很细,但结合应用实际使用场景发现,界面的切换相对频繁,组件频繁载入和卸载的开销会很大,而且将耦合紧密的组件拆到不同的视图,需要记录很多状态信息,有点得不偿失,最终作罢,没有将主视图继续分下去。考虑到三个视图的访问重叠性不高,自然就需要将组件做成异步加载,只在访问到的时候才加载组件,Vue自身支持异步组件,所以这件事变得非常简单,只要能返回一个Promise,你可以使用任意方式获取组件。

接下来要接入野狗云,实现真正的用户管理和数据统计,野狗云可以提供用户鉴权和数据存储等一系列功能,通过它只需要用js就可以开发一个完整的WEB应用。这样之前所有对localStorage的操作都要改成对野狗云的操作,数据到了云端也变得更可靠了。

至此二次重构就完成了,业务代码总体感觉减少了很多,但总代码量估计没少多少,毕竟还增加了三个框架文件,不过经过重重拆分,文件数量从当初的三两个js变成了十来个js,模块化方面用的seajs而不是webpack,因为个人对 webpack仍然持观望态度,目前还感觉不到用它的必要性,关键是基于webpack开发的代码会夹杂很多私货,让你的代码变得不原生,离了他就运行不起来,这个我不太能接受,而且在多页面场景seajs配合本地缓存比webpack更有优势,当然了,他们的的区别就跟jQuery和Vue的区别一样,本质不是一个东西,关键在于使用场景,适合的就是最好的。

后记

经过两次重构的实践和踩坑,对Vue框架有了更深刻的认识,Vue想要用的灵活自如,对开发者的项目架构能力有一个最低要求,如果要将Vue引入底层,对基础设施建设者的规划能力也有一个最低要求,这些都是jQuery技术栈所不存在的,使用Vue的过程也是接受这些约束的过程,他们能引导开发者建立自己的规则体系,这是好事也是大势所趋,毕竟真正的自由只存在于规则中。

本文的完整代码见Github。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
一个加密JavaScript的开源工具PACKER2.0.2
Nov 04 Javascript
一段利用WSH获取登录时间的jscript代码
May 11 Javascript
WEB页子窗口(showModalDialog和showModelessDialog)使用说明
Oct 25 Javascript
使用JQuery库提供的扩展功能实现自定义方法
Sep 09 Javascript
jQuery CSS()方法改变现有的CSS样式表
Sep 09 Javascript
JS+DIV实现鼠标划过切换层效果的方法
May 25 Javascript
JavaScript判断表单为空及获取焦点的方法
Feb 12 Javascript
基于bootstrap插件实现autocomplete自动完成表单
May 07 Javascript
js正则表达式最长匹配(贪婪匹配)和最短匹配(懒惰匹配)用法分析
Dec 27 Javascript
AngularJS基于provider实现全局变量的读取和赋值方法
Jun 28 Javascript
vue params、query传参使用详解
Sep 12 Javascript
JavaScript中变量提升与函数提升经典实例分析
Jul 26 Javascript
浅谈Vuex的状态管理(全家桶)
Nov 04 #Javascript
简述Angular 5 快速入门
Nov 04 #Javascript
vue2.0在table中实现全选和反选的示例代码
Nov 04 #Javascript
vue中使用localstorage来存储页面信息
Nov 04 #Javascript
javascript+jQuery实现360开机时间显示效果
Nov 03 #jQuery
原生JavaScrpit中异步请求Ajax实现方法
Nov 03 #Javascript
使用 Javascript 实现浏览器推送提醒功能的示例
Nov 03 #Javascript
You might like
使用PHP实现阻止用户上传成人照片或者裸照
2014/12/25 PHP
推荐十款免费 WordPress 插件
2015/03/24 PHP
Javascript模块模式分析
2008/05/16 Javascript
JavaScript 字符串与数组转换函数[不用split与join]
2009/12/13 Javascript
Javascript 面向对象 命名空间
2010/05/13 Javascript
javascript记录文本框内文字个数检测文字个数变化
2014/10/14 Javascript
jquery常用函数与方法汇总
2015/09/01 Javascript
JavaScript转换与解析JSON方法实例详解
2015/11/24 Javascript
jQuery实现下拉加载功能实例代码
2016/04/01 Javascript
jQuery实现在HTML文档加载完毕后自动执行某个事件的方法
2017/05/08 jQuery
js原生代码实现轮播图的实例讲解
2017/07/28 Javascript
详解基于vue-cli配置移动端自适应
2018/01/13 Javascript
JavaScript异步加载问题总结
2018/02/17 Javascript
node实现的爬虫功能示例
2018/05/04 Javascript
Bootstrap Table列宽拖动的方法
2018/08/15 Javascript
js实现按钮开关单机下拉菜单效果
2018/11/22 Javascript
Vue监听页面刷新和关闭功能
2019/06/20 Javascript
原生js实现密码强度验证功能
2020/03/18 Javascript
浅析JavaScript 函数防抖和节流
2020/07/13 Javascript
PHP网页抓取之抓取百度贴吧邮箱数据代码分享
2016/04/13 Python
Python numpy 点数组去重的实例
2018/04/18 Python
实例讲解Python爬取网页数据
2018/07/08 Python
基于python实现上传文件到OSS代码实例
2020/05/09 Python
python virtualenv虚拟环境配置与使用教程详解
2020/07/13 Python
容易被忽略的Python内置类型
2020/09/03 Python
html5的canvas方法使用指南
2014/12/15 HTML / CSS
出门问问全球官方商城:Tichome音箱和TicWatch智能手表
2017/12/02 全球购物
荷兰在线体育用品商店:Avantisport.nl
2018/07/04 全球购物
童装店创业计划书
2014/01/09 职场文书
新郎父亲婚宴答谢词
2014/01/11 职场文书
2014幼儿园大班工作总结
2014/11/10 职场文书
教师年度考核个人总结
2015/02/12 职场文书
2016年师德学习心得体会
2016/01/12 职场文书
解决python存数据库速度太慢的问题
2021/04/23 Python
sql查询结果列拼接成逗号分隔的字符串方法
2021/05/25 SQL Server
浅谈Go语言多态的实现与interface使用
2021/06/16 Golang