前端技术的发展可谓突飞猛进,更有甚者,在deno开源项目的issue中发“求不要更新了,老子学不动了”,这新闻传遍中国的技术圈子,有人说这是中国人的耻辱。这里我就不评论好坏。但可见,前端发展的速度很是惊人。
但“存在即合理”,黑格尔的这句话,在技术领域更加是。可以发展的技术,必定更人们带来便利。扩大解决问题的范围,或者是提升解决需求的速度等等。
然而对于后台人员,面对遗留下来的后台系统,并无彻底先后端分离,也有公司只有后台人员,先后端都干。那么问题来了,上述这种状况下如何提升效率呢。引入Angular、React、Vue是能解决效率问题,得益于其MVVM技术将视图UI和业务逻辑分开等四大特性:css
上述特性是否是抽象,前端人员都以为前端技术发展之快,后端人员就更难接触和体会。vue官网的例子更是以webpack等模块化例子来说解,这样以来,若是想使用vue的好处而已,还要去了解webpack、AMD等等,这让后端人员再三地望而却步。
除了技术栈的限制,项目时间也是个门槛,虽然我以为前端不少思想都是源自于后端的思想,如模块化,mvc,构建技术等,但学起来仍是要时间呢。老板并不会给时间开发人员去把整个前端推倒了重干。推倒重干也不切实际,一成本高,二风险大(如能不能完成,或能不能赶在市场机会面前完成)。因此渐进地改变是比较稳妥的(保守主义)。html
因此这里分享下我在老项目快速应用vue的经验。前端
在原有有项目的html页面里,引入vue的依赖vue
<!-- Vue.js v2.5.16 --> <script src="/js/vue/vue.min.js"></script> <!-- vue-resource v1.5.1 用于ajax请求--> <script src="/js/vue/vue-resource.min.js"></script>
本例子是一个添加用户表单的提交,就只有使用几个属性 v-model,v-for和v-on:click,以及{{}}占位符
此时html代码只需修改以下(专一于展现):node
<div class="form-horizontal" method="post" id="userFrom"> <div class="form-group"> <input type="text" class="form-control" id="name" placeholder="请输入用户帐号" v-model="name" > </div> <div class="form-group"> <input type="password" class="form-control" id="name" placeholder="请输入用户密码" v-model="name" > </div> <div class="form-group"> <button type="button" class="btn btn-success" data-toggle="modal" data-target="#myModal">选择角色</button> <table class="table table-hover" > <thead> <tr> <th>操做</th> <th>角色ID</th> <th>角色名称</th> </tr> </thead> <tbody> <tr v-for="(item,index) in nodeList"> <td> <button type="button" class="btn btn-danger" v-on:click="remove($event,index)">移除</button> </td> <th scope="row">{{ item.id }}</th> <td>{{ item.name }}</td> </tr> </tbody> </table> </div> <div class="form-group"> <textarea placeholder="请输入备注" name="remark" id="remark" v-model="remark"></textarea> </div> <div class="form-group"> <div class="col-xs-2"> <button class="btn btn-primary btn-block btn-flat" v-on:click="createUser">添加</button> </div> </div> </div> <!-- 弹出框,选择角色,上面的选择角色按钮则弹出如下对话框,这个是boostra技术的范畴,但不影响vue的使用 --> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true"> × </button> <h4 class="modal-title" id="myModalLabel"> 选择角色 </h4> </div> <div class="modal-body"> <table class="table table-hover" id="toChooseTable"> <thead> <tr> <th>操做</th> <th>角色ID</th> <th>角色名称</th> </tr> </thead> <tbody> <tr v-for="(item,index) in toChooseList"> <td> <button type="button" class="btn btn-danger" v-on:click="choose($event,index)">选择</button> </td> <th scope="row">{{ item.id }}</th> <td>{{ item.name }}</td> </tr> </tbody> </table> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">关闭 </button> </div> </div><!-- /.modal-content --> </div><!-- /.modal --> </div>
script代码修改(专一于数据及其操做)webpack
<script > //提交表单中的数据及操做 var userFrom = new Vue({ el: '#userFrom', data: { name:'', password:'', remark:'', roleList: [], apiUrl: '/user/add' }, // 在 `methods` 对象中定义方法 methods: { remove: function (event,index) { //移除角色 //1.将未被选择的角色数据放回弹出框内 pushToChooseList(this.roleList[index]); //2.在已选择的角色table里移除这个角色数据 this.roleList.splice(index,1); }, createUser: function() { var params = { name:this.name, password:this.password, remark:this.remark, roleList:[] }; for(var i=0;i<this.roleList.length;i++){ var role={}; role.id = this.roleList[i].id; role.name = this.roleList[i].name; params.roleList.push(node); } this.$http.post(this.apiUrl,JSON.stringify(params),{ emulateJSON:false }).then(function(response){ // response.data中获取ResponseData实体 console.log(response); },function(response){ // 发生错误 console.log(response); }); } } }) //弹出框数据及操做 var toChooseTable = new Vue({ el: '#toChooseTable', data: { toChooseList: [ ], apiUrl: '/role/list' }, // 在 `methods` 对象中定义方法 methods: { loadData: function() { //加载角色数据 this.$http.post(this.apiUrl, {}).then(function (response) { var result = response.data; for (var i = 0; i < result.data.length; i++) { var role = {}; role.id = result.data[i].id; role.name = result.data[i].name; toChooseTable.toChooseList.push(node); } }, function () { console.log('failed'); }); }, choose: function (event,index) //选择角色 //1.将选择的角色数据放入被选中的table里 pushChoosedList(this.toChooseList[index]); //2.移除已被选择的弹出框的角色数据 this.toChooseList.splice(index,1); } } }) //加载角色数据 toChooseTable.loadData(); function pushChoosedList(data) { for(j = 0,len=userForm.roleList.length; j < len; j++) { if(userForm.roleList[j].id==data.id){ return; } } userForm.roleList.push(data); } function pushToChooseList(data) { for(j = 0,len=toChooseTable.toChooseList.length; j < len; j++) { if(toChooseTable.toChooseList[j].id==data.id){ return; } } toChooseTable.toChooseList.push(data); } </script>
上述例子很好的展现视图层和数据层的分离,视图和数据层都是单独分开写的,不知道你能不能从中体会到效率的提升。之前这种弹出框选中数据,在table列表中展现,但是要写好多js代码,需手工建立tr标签,而后再append进table标签等,还要遍历定位标签,反正写个页面都老半天。有了vue,这效率简直大大的提升了。web
上述例子中,咱们体会到视图层和数据层的分离,但还不是很理解模块化复用,如下就举个模块化复用好处的例子,就是使用element-ui的列表及分页。ajax
引入element-ui
在上述vue基础上,引入:npm
<!-- 引入样式 --> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <!-- 引入组件库_element-ui@2.4.4@element-ui,官网不提供直接下载,需用cnpm i element-ui -S下载,而后复制lib目录 --> <script src="https://unpkg.com/element-ui/lib/index.js"></script>
只须要引入element-ui的table组件和分页组件,便可达到复用
修改html代码:element-ui
<div class="ibox-content" id="content"> <!-- table组件 参考:http://element-cn.eleme.io/#/zh-CN/component/table--> <el-table :data="tableData" style="width: 100%"> <el-table-column label="日期" width="180"> <template slot-scope="scope"> <i class="el-icon-time"></i> <span style="margin-left: 10px">{{ scope.row.date }}</span> </template> </el-table-column> <el-table-column label="姓名" width="180"> <template slot-scope="scope"> <el-popover trigger="hover" placement="top"> <p>姓名: {{ scope.row.name }}</p> <p>住址: {{ scope.row.address }}</p> <div slot="reference" class="name-wrapper"> <el-tag size="medium">{{ scope.row.name }}</el-tag> </div> </el-popover> </template> </el-table-column> <el-table-column label="操做"> <template slot-scope="scope"> <el-button size="mini" @click="handleEdit(scope.$index, scope.row)">编辑</el-button> <el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button> </template> </el-table-column> </el-table> <!-- 分页组件--> <div align="center"> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="page" :page-sizes="[10, 20, 30, 40]" :page-size="rows" layout="total, sizes, prev, pager, next, jumper" :total="totalRecord"> </el-pagination> </div> </div>
修改script代码
<script > /*<![CDATA[*/ var content = new Vue({ el: '#content', data: { tableData: [{ date: '2016-05-02', name: '王小虎', address: '上海市普陀区金沙江路 1518 弄' }, { date: '2016-05-04', name: '王小虎', address: '上海市普陀区金沙江路 1517 弄' }, { date: '2016-05-01', name: '王小虎', address: '上海市普陀区金沙江路 1519 弄' }, { date: '2016-05-03', name: '王小虎', address: '上海市普陀区金沙江路 1516 弄' }], url:'/user/list', //搜索条件 criteria: '', //下拉菜单选项 select: '', //默认每页数据量 rows: 10, //当前页码 page: 1, //查询的页码 start: 1, //默认数据总数 totalRecord: 1000 }, // 在 `methods` 对象中定义方法 methods: { loadData: function(criteria, pageNum, pageSize){ this.$http.post(this.url,{criteria:criteria, page:pageNum, rows:pageSize},{emulateJSON:true}).then(function(res){ var page = res.data; this.tableData = page.data; this.totalRecord = page.totalRecord; },function(){ console.log('failed'); }); }, handleEdit: function (index, row) { console.log(index, row); }, handleDelete: function (index, row) { console.log(index, row); }, //每页显示数据量变动 handleSizeChange: function(val) { this.rows = val; this.loadData(this.criteria, this.page, this.rows); }, //页码变动 handleCurrentChange: function(val) { this.page = val; this.loadData(this.criteria, this.page, this.rows); } } }) //加载数据 content.loadData(content.criteria, content.page, content.rows); /*]]>*/ </script>
虽然没有使用webpack更完全的模块化。但上述的列子,也够给老项目带来复用的效率提高,后台人员不用花时间去调样式。