接上篇,在本篇中,我們將要實現如下,功能,編輯和查詢,我們當前的todolist程序,和線上其它的demo程序不同,我們會對其進行增刪改查的基本操作,之后進行進一步的完善,按照常規的系統使用經驗,一般我們新增和編輯都是在模態框中處理,這里我們不會去構建復雜的模態框,只用一個簡單的div層來代替,后期接下來的文章中我們會重復造輪子,構建我們自己的輕量級框架(UI庫)。
首先,我們對我們的頁面結構進行一下簡單的調整,加入bootstrap只是為了讓頁面不那么赤裸裸,對其它不會有任何影響
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>demo1</title> <script src="https://cdn.bootcss.com/vue/2.4.1/vue.js"></script> <link  rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet"></head><body class="container"> <div id="app" class='row'> <div class="col-md-6">  <table class="table table-bordered">  <tr>   <th>title</th>   <th>desc</th>   <th></th>  </tr>  <tr v-for="(todoItem,index) in todolist">   <td>{{todoItem.title}}</td>   <td>{{todoItem.desc}}</td>   <td><input type="button" value="remove" @click="remove(index)" class="btn btn-danger" /></td>  </tr>  </table> </div> <div class="col-md-6">  <div class="form-inline">  <label for="title" class="control-label col-md-4">title:</label>  <input type="text" v-model="title" class="form-control col-md-8">  </div>  <div class="form-inline">  <label for="desc" class="control-label col-md-4">desc</label>  <input type="text" v-model="desc" class="form-control col-md-8">  </div>  <div class="form-inline">  <input type="button" value="OK" v-on:click="addItem()" class="btn btn-primary offset-md-10" />  </div> </div> </div> <script> var TodoItem = function (title, desc) {  this.title = title;  this.desc = desc; } new Vue({  el: '#app',  data: {  todolist: [],  title: '',  desc: ''  },  methods: {  addItem: function () {   this.todolist.push(new TodoItem(this.title, this.desc))   this.title = this.desc = '';  },  remove: function (index) {   this.todolist.splice(index, 1);  }  } }) </script></body></html>js沒有任何變化,只是引入了bootstrap4之后,對html結構進行了微調整,由于我們需要增加編輯操作,我們把增加編輯操作歸納為以下幾個步驟:
1、增加編輯按鈕;
2、點擊編輯按鈕綁定所對應todoitem到表單進行編輯
3、點擊表單中OK按鈕,對編輯結果進行應用。
注意:這里需要區分,在點擊OK按鈕時,進行的是新增操作還是編輯操作,我們對我們數據結構加入自增ID來標示,如果編輯項目有ID,則為保存編輯操作,如果不存在ID則為新增保存操作,對我們的數據結構進行以下微調,由于新增了ID項目,那么在data屬性中也要增加ID屬性,這樣每次新增屬性都要直接修改data屬性,這就是變化點,下面我們對變化點進行簡單封裝,修改代碼如下:
data: {  todolist: [],  todoItem:{   id:'',   title:'',   desc:''  }  },另外我們需要實現自增ID,這里采用最直接的方式,全局ID,使其自增即可,對TodoItem進行簡單的閉包處理:
var TodoItem = (function () {  var id = 1;  return function (title, desc) {  this.title = title;  this.desc = desc;  this.id = id++;  } })();為了適應新數據結構的變化,則其它修改部分整體貼出來,變化部分見黃色:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>demo1</title> <script src="https://cdn.bootcss.com/vue/2.4.1/vue.js"></script> <link  rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet"></head><body class="container"> <div id="app" class='row'> <div class="col-md-6">  <table class="table table-bordered">  <tr>   <th></th>   <th>title</th>   <th>desc</th>   <th></th>  </tr>  <tr v-for="(todoItem,index) in todolist">   <th>{{todoItem.id}}</th>   <td>{{todoItem.title}}</td>   <td>{{todoItem.desc}}</td>   <td><input type="button" value="remove" @click="remove(index)" class="btn btn-danger" /></td>  </tr>  </table> </div> <div class="col-md-6">  <div class="form-inline">  <label for="title" class="control-label col-md-4">title:</label>  <input type="hidden" v-bind:value="todoItem.id" />  <input type="text" v-model="todoItem.title" class="form-control col-md-8">  </div>  <div class="form-inline">  <label for="desc" class="control-label col-md-4">desc</label>  <input type="text" v-model="todoItem.desc" class="form-control col-md-8">  </div>  <div class="form-inline">  <input type="button" value="OK" v-on:click="addItem()" class="btn btn-primary offset-md-10" />  </div> </div> </div> <script> var TodoItem = (function () {  var id = 1;  return function (title, desc) {  this.title = title;  this.desc = desc;  this.id = id++;  } })(); new Vue({  el: '#app',  data: {  todolist: [],  todoItem: {   id: '',   title: '',   desc: ''  }  },  methods: {  addItem: function () {   // this.todolist.push(new TodoItem(this.title, this.desc))   this.todolist.push(   new TodoItem(    this.todoItem.title,    this.todoItem.desc   )   );   this.todoItem={};  },  remove: function (index) {   this.todolist.splice(index, 1);  }  } }) </script></body></html>刷新頁面,測試效果如下:

自增ID已經完成,那么添加編輯時綁定,按照上面的步驟,先添加編輯按鈕,在刪除按鈕后添加編輯按鈕,并在methods對象中增加對應的回調函數,對edit操作進行響應,函數中主要實現對todoItem對象進行綁定操作,具體代碼修改如下:
<table class="table table-bordered">  <tr>   <th></th>   <th>title</th>   <th>desc</th>   <th></th>  </tr>  <tr v-for="(todoItem,index) in todolist">   <th>{{todoItem.id}}</th>   <td>{{todoItem.title}}</td>   <td>{{todoItem.desc}}</td>   <td>   <input type="button" value="remove" @click="remove(index)" class="btn btn-danger" />   <input type="button" value="edit" @click="edit(todoItem.id)" class="btn btn-info" />   </td>  </tr>  </table>methods: {    edit: function (id) {     //找到id值等于所傳參數的todoitem     var obj = this.todolist.filter(v => v.id === id)[0];     //對數據進行綁定,則數據會響應到表單上     this.todoItem = obj;    },   ...省略其它}這樣有沒有問題呢?我們運行看一下效果:

從運行結果上看,我們點擊edit操作,的確完成了綁定,但是在我們修改編輯,還沒有點擊OK按鈕的情況下,表單中的變化已經提現到了列表中,這就不符合正常邏輯了,為什么會有這樣的情況呢,原因就在于this.todoItem=obj;這句代碼就是所謂的引用賦值,所以todoitem和obj指向的是同一個地址,則對this.todoItem的修改,會直接反應到obj上,也就是todoList中的這個元素上,所以在列表中會直接提現出來,避免這種情況的發生的方法,只要避免飲用賦值即可,所以對上述代碼進行如下修改:
//找到id值等于所傳參數的todoitem   var obj = this.todolist.filter(v => v.id === id)[0];   //對數據進行綁定,則數據會響應到表單上   this.todoItem = {   id:obj.id,   title:obj.title,   desc:obj.desc   };刷新運行,發生程序按照預期運行了,接下來,增加更新保存操作,修改OK按鈕的事件綁定方式為save,并通過id判斷新增還是修改操作:
<div class="col-md-6"> <div class="form-inline"> <label for="title" class="control-label col-md-4">title:</label> <input type="hidden" v-bind:value="todoItem.id" /> <input type="text" v-model="todoItem.title" class="form-control col-md-8"> </div> <div class="form-inline"> <label for="desc" class="control-label col-md-4">desc</label> <input type="text" v-model="todoItem.desc" class="form-control col-md-8"> </div> <div class="form-inline"> <input type="button" value="OK" v-on:click="save()" class="btn btn-primary offset-md-10" /> </div> </div>
methods: {  edit: function (id) {   //找到id值等于所傳參數的todoitem   var obj = this.todolist.filter(v => v.id === id)[0];   //對數據進行綁定,則數據會響應到表單上   this.todoItem = {   id: obj.id,   title: obj.title,   desc: obj.desc   };  },  save: function () {   if (this.todoItem.id) {   //編輯保存   var obj = this.todolist.filter(v => v.id === this.todoItem.id)[0];   obj.title = this.todoItem.title;   obj.desc = this.todoItem.desc;   } else {   //新增保存   this.todolist.push(    new TodoItem(    this.todoItem.title,    this.todoItem.desc    )   );   }   //重置表單 這部分筆誤,在實際代碼中已修改,但是貼上來的代碼沒有做修改,具體見最下面代碼,錯誤原因見下方回復   this.todoItem = {};  },    remove: function (index) {   this.todolist.splice(index, 1);  }  }代碼比較簡單,這里就不再贅述,可以看一下運行效果:

為了逼格更高一點,這里我再介紹一個指令,其實上面已經使用了,v-bind ,這個指令和v-on是類似的,兩者的區別在于后面的參數不同,一般v-bind用來傳遞屬性參數,一般使用縮寫形式:attr,可以綁定自定義屬性,上面代碼中我們對Id值的綁定已經使用了v-bind:value="todoItem.id",這里相當于angular中ng-bind。基于對v-bind的了解,我們可以推理,給v-bind添加disable的屬性,使OK按鈕只有再title不為空的前提下再可用。
<div class="form-inline"> <input type="button" value="OK" v-on:click="save()" class="btn btn-primary offset-md-10" :disabled='!todoItem.title'/> </div>
刷新運行:

上面代碼能很好的運行,但是現在如果我需要修改一下驗證規則,在title和desc都不為空的情況下,才使用OK按鈕可用,如何做?你當然會說,很簡單,直接加入一個&&條件不就行了,但是問題在于,現在我的模型比較小,屬性比較少,如果我存在一個大量屬性的對象,做類似的驗證,這樣來修改代碼就是一個坑了,說到這里,其實已經可以想到,既然驗證規則再變,那么可以考慮作為一個變化點封裝起來,最直觀的方式,是封裝為一個方法,但是vue提供了更好的方式:computed,計算屬性,這個計算屬性應該是來自于knockout的概念,有興趣的可以看一下knockout中計算屬性,修改代碼如下:
new Vue({  el: '#app',  data: {  todolist: [],  todoItem: {   id: '',   title: '',   desc: ''  }  },  computed:{  canSave:function(){   return !this.todoItem.title || !this.todoItem.desc;  }  },  ...省略其它  } })可以看到computed屬性是以方法的方式來定義的,這里是最簡單方式,只讀的方式,當然還可以通過get set方式進行讀寫控制,我們后期的代碼中可能會見到,如果捉急,可以去查看官方文檔。在computed使用的時候,和方法調用截然不同,而是和data屬性中代理的模式一樣,如果你使用過knockout,那么你對這種用法就見怪不怪了,html部分修改如下:
<div class="form-inline"> <input type="button" value="OK" v-on:click="save()" class="btn btn-primary offset-md-10" :disabled='canSave'/> </div>
刷新頁面,運行效果如圖:

ok,編輯這部分內容就到這里吧,在沒有后端接口的前提下,保存操作都是模擬的,接下來對我們的查詢進行一下簡單的介紹,這里查詢,由于沒有后端接口,咱們只做最簡單的演示,對代碼做如下處理:
1、增加查詢輸入框,keyword,添加查詢按鈕
2、點擊查詢操作,預期結果:根據輸入的查詢關鍵字,過濾列表
按照上面思路對我們代碼進行修改:
<div class="row toolbar"> <div class="col-md-8"> keyword: <input type="text" v-model="keyword" /> <input type="button" @click="query()" value="search" /> </div> </div>
data中增加keyword屬性,以實現對輸入框的綁定,在methods中添加query方法:
//全局變量,用來緩存所有數據 var list = []; data: {  todolist: [],  todoItem: {   id: '',   title: '',   desc: ''  },  keyword:''  },query: function () {   //過濾title中不包含keyword的數據   //這里必須通過list全局變量過濾,而不能通過this.todolist,因為需要給this.todolist賦值,賦值后無法還原原來的列表。   this.todolist = list.filter(v => v.title.indexOf(this.keyword) !== -1);  }刷新頁面運行效果如圖:

代碼部分注釋中已經寫的很清楚了,有疑問可提價comment。本章就到這里,文章有點水,在(三)中會加入添加服務端支持,并使用axios和服務端rest接口進行交互敬請期待,準備睡覺。
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>demo1</title> <script src="https://cdn.bootcss.com/vue/2.4.1/vue.js"></script> <link  rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet"></head><body class="container"> <div id="app"> <div class="row toolbar">  <div class="col-md-8">  keyword:  <input type="text" v-model="keyword" />  <input type="button" @click="query()" value="search" />  </div> </div> <div class='row'>  <div class="col-md-6">  <table class="table table-bordered">   <tr>   <th></th>   <th>title</th>   <th>desc</th>   <th></th>   </tr>   <tr v-for="(todoItem,index) in todolist">   <th>{{todoItem.id}}</th>   <td>{{todoItem.title}}</td>   <td>{{todoItem.desc}}</td>   <td>    <input type="button" value="remove" @click="remove(index)" class="btn btn-danger" />    <input type="button" value="edit" @click="edit(todoItem.id)" class="btn btn-info" />   </td>   </tr>  </table>  </div>  <div class="col-md-6">  <div class="form-inline">   <label for="title" class="control-label col-md-4">title:</label>   <input type="hidden" v-bind:value="todoItem.id" />   <input type="text" v-model="todoItem.title" class="form-control col-md-8">  </div>  <div class="form-inline">   <label for="desc" class="control-label col-md-4">desc</label>   <input type="text" v-model="todoItem.desc" class="form-control col-md-8">  </div>  <div class="form-inline">   <input type="button" value="OK" v-on:click="save()" class="btn btn-primary offset-md-10" :disabled='canSave' />  </div>  </div> </div> </div> <script> var list=[]; var TodoItem = (function () {  var id = 1;  return function (title, desc) {  this.title = title;  this.desc = desc;  this.id = id++;  } })(); new Vue({  el: '#app',  data: {  todolist: [],  todoItem: {   id: '',   title: '',   desc: ''  },  keyword: ''  }, computed: {  canSave: function () {   return !this.todoItem.title || !this.todoItem.desc;  }  },  methods: {  query: function () {   //過濾title中不包含keyword的數據   //這里必須通過list全局變量過濾,而不能通過this.todolist,因為需要給this.todolist賦值,賦值后無法還原原來的列表。   this.todolist = list.filter(v => v.title.indexOf(this.keyword) !== -1);  },  edit: function (id) {   //找到id值等于所傳參數的todoitem   var obj = this.todolist.filter(v => v.id === id)[0];   //對數據進行綁定,則數據會響應到表單上   this.todoItem = {   id: obj.id,   title: obj.title,   desc: obj.desc   };  },  save: function () {   if (this.todoItem.id) {   //編輯保存   var obj = this.todolist.filter(v => v.id === this.todoItem.id)[0];   obj.title = this.todoItem.title;   obj.desc = this.todoItem.desc;   } else {   //新增保存   this.todolist.push(    new TodoItem(    this.todoItem.title,    this.todoItem.desc    )   );   }   //重置表單   this.todoItem = { title: '', desc: '' };  },  remove: function (index) {   this.todolist.splice(index, 1);  }  } }) </script></body></html>以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。
新聞熱點
疑難解答