前端技術的發展可謂突飛猛進,更有甚者,在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更完全的模塊化。但上述的列子,也夠給老項目帶來複用的效率提高,後臺人員不用花時間去調樣式。