接触vue已经一段时间了,虽然框架的便利和特性让人眼馋,但还是迟迟没法应用到实际项目中,究其原因,主要是网上介绍vue实际应用的教程基本都是一整套全家桶压过来,如我一般知识不全面的小白很难一下子跨进去,最终往往在知识准备阶段就耗光了热情。所以,我打算从手头的旧项目着手,一点一点进行改造,一口吃不掉,那就小口慢咬,即所谓“蚕食”。过程中也会遇到一些小坎儿,我会把这期间的思路和考量写出来,希望能得到一些有营养的指点和交流。
前置知识:对vue的基本指令有点儿了解即可。
1、项目简介
首先简单介绍一下要改造的项目,是个数据管理系统,涉及到大量的数据展示、修改提交等行为,与vue标榜的数据驱动还是很有契合点的。
2、项目改造
因为第一个界面(左上角)目前正在调改,所以我以它作为改造对象。改造思路大致如下:
实际操作时,我喜欢一个一个知识点去改,感觉这样更利于知识的吸收和个人成长,而且也基本不会影响在运行项目的正常使用,破坏的可能性最小。OK,从易到难走起~~
1)基本结构搭建
① 在页面中引入框架:<script src="../lib/vue.min.js"></script>
② 创建Vue实例:var vm = new Vue({el:"#VueApp",data:{},computed:{},methods:{}});
2)使用{{}}取代dom操作
繁杂的DOM操作(命名id、获取元素、操作元素...)一直是很多前端er的一个痛点,使用{{}}可以很大程度上缩减代码量,更有利于后期维护,更重要的是——不用再为命名id发愁了。{{}}的修改比较容易,我简单举个例子,比如修改右上方的“姓名、性别...”
① 在 vm > data 中设置PatientInfo:{PatientName:"",PatientSex:"",PatientBir:"",PatientCardId:""}
② 在 html 中使用 v-text 对绑定数据 <span v-text="PatientInfo.PatientName"></span>
对于①,在实际项目中,后端接口会直接返回一个对象,对象的内容即上方PatientInfo的内容,所以实际改造中,我是将PatientInfo设置为空对象(节省代码嘛);
对于②,之所以使用 v-text 而不是 {{}},首先当然是为了避免页面加载时空白时间过长,所以我不希望在Vue实例的根元素上使用 v-cloak,同时也不希望在页面中的分支节点上设置很多 v-cloak ,毕竟页面中的元素哪怕能早1-2秒展示都会让人更舒心,所以不到不得已,能避则避。
稍微复杂的修改,最多也只涉及到过滤器,以iframe中的“检查日期”为例,后端接口返回的日期是带着毫秒的(2017-08-20 16:23:12.175),这时可在 Vue 实例前创建个全局过滤器(因为其它页面也会用到所以先建个全局的)。
创建过滤器:Vue.filter("date",function(value){return value?value.split('.')[0]:''});
使用过滤器:<span>{{ NewResult.ClientTime | date }}<span>
值得注意的是 v-text 和 v-html 中不能使用过滤器,所以只能如上写在{{}}中,后续需要使用 v-cloak 优化一下用户体验。
3)使用v-model优化表单
自从 Angular 提出双向绑定开始,这个功能就几乎成为后续框架的必备(Vue中就是 v-model 了)。做这个调改时我还是比较兴奋的,因为可以减少大量的表单dom操作,同时在这个示例项目还别有一番好处。具体情况如下:
上图所示主展示区是个 iframe ,它左上角的第四个按钮的作用是“添加检查记录”(即表单的填写提交)。类似的页面目前有30多个(与上方的设备列表一一对应),每个表单的字段自然也各不相同(如图 3-1)。
之前 jQuery 的做法是为每个表单单独写一个提交函数,这代码量相当吓人。现在使用Vue,我的做法是让这n多的表单共用一个函数(前提是它们使用的接口相同,只是提交的参数有区别):
① 初始化页面时先在Vue实例中声明一个变量(JSON格式),它包含所有表单的字段及初始值(如图 3-2),同时深拷贝一个作为备份,用于提交表单后对表单内容进行重置;
② 将上述提到的变量中的表单字段与页面中的输入框绑定好,之后当用户填完表单时,借助 v-model 的双向绑定变量的值也相应会自动整理妥当。待要上传时直接通过序号从变量中调取相应表单的数据提交即可(如图 3-3)。
③ 至于数据校验,因为本项目中大多数表单内容为数字,所以主要使用 html5 自带的表单校验(如:min、max、step、required等),文本使用 v-model.trim 修饰符。当然还是有一些内容需要自定义规则校验的,这个就需要根据实际情况在调取到相关表单数据后做点小处理。
4)template/v-if组合
既然提到表单,就先说说表单弹窗吧。这里我主要考虑了这么几种方式:
① 最初表单只有不到10个,当时是全部放在外层页面内,每个表单单独有一个弹窗结构(虽然使用 bootstrap 会导致相关的 html 代码会比较多,但还可以忍受),但就目前的情况而言,这种方式会导致外层页面代码过肥。
② 将每个设备对应的表单弹窗代码放到各自的 iframe 页面中,待用户切换到该设备下时,再将表单弹窗从iframe中拿到外层页面中,这种方式我使用了一段时间,但心理上觉得这样取来取去的挺不安心的。
③ 现在我是将所有弹窗还放在外层页面,然后因为每个表单头尾相同,且表单中都有“姓名、日期”条目,所以将他们放在一个弹窗结构中,使用 “template、v-if、v-else-if”(如<template v-if="CurrentEnumId==1">)来包裹切换中间不同的部分。代码量压缩了20K,但是还是很肥(70K),后来也相关把弹窗做成组件从页面中分离出去,不过因为时间关系暂且这样了。
在使用 template 时有一点需要注意:当在 table 中使用 template 标签时,IE浏览器是不认的,针对这个问题,我考虑以后将弹窗内容较多的几个块做成组件,然后用 <tr is="xxx"> 引入,不过目前还在思考寻觅其它解决方案。
5)用组件优化重复的代码块
从图1-1和2-1中可以看到,不同页面调用了某些相同的区块,这些区块都很适合做成组件,此处我以“图片上传预览”为例(在多个表单中都有如图3-1的图片上传预览功能)。这里我先结合组件所需功能说说思路:
① 初始时,组件显示如图3-1所示灰色色块,当点击色块时触发选择图片窗口,选中图片并确定后,图片自动上传到后台并返回图片地址(提交表单时要用),接着再去除灰色色块展示图片,这时当鼠标hover图片时灰色色块半透明显示(因为上面要展示点文字信息)。
② 允许拖拽上传。
从上述功能中可以梳理出所需的变量如下:ImgSrc(图片地址)、labelStyle(灰色色块的状态)、ShowImg(控制图片的显示,只有在加载正确时才显示)、ImgStyle(控制图片的样式,确保图片无论是横条还是竖条都能水平垂直居中)、drag(用来存储拖拽的文件信息,以便在多个函数间共享)
至于要接收的参数和输出的参数,可根据实际情况而定,我这里只设置了从外层接收数据,“输出”直接修改了实例的数据。建议还是使用 $emit 触发实例中的方法。
值得注意的是:使用组件时最好使用 <div is="xxx"> 的方式,而不要使用自定义的标签名,因为在IE下可能报错“无效标签”。
目前已经按照图2-1所示的思路完成修改,测试时尚未发现什么大问题。除上述指令和方法外,其它涉及到的常用但简单的指令还有:v-for、v-show、v-on、v-bind等。
请多多指导,谢谢(未完待续...)