前端主流框架vue學(xué)習(xí)筆記第二篇
接上篇,在本篇中,我們將要實(shí)現(xiàn)如下,功能,編輯和查詢,我們當(dāng)前的todolist程序,和線上其它的demo程序不同,我們會(huì)對(duì)其進(jìn)行增刪改查的基本操作,之后進(jìn)行進(jìn)一步的完善,按照常規(guī)的系統(tǒng)使用經(jīng)驗(yàn),一般我們新增和編輯都是在模態(tài)框中處理,這里我們不會(huì)去構(gòu)建復(fù)雜的模態(tài)框,只用一個(gè)簡單的div層來代替,后期接下來的文章中我們會(huì)重復(fù)造輪子,構(gòu)建我們自己的輕量級(jí)框架(UI庫)。
首先,我們對(duì)我們的頁面結(jié)構(gòu)進(jìn)行一下簡單的調(diào)整,加入bootstrap只是為了讓頁面不那么赤裸裸,對(duì)其它不會(huì)有任何影響
<!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之后,對(duì)html結(jié)構(gòu)進(jìn)行了微調(diào)整,由于我們需要增加編輯操作,我們把增加編輯操作歸納為以下幾個(gè)步驟:
1、增加編輯按鈕;
2、點(diǎn)擊編輯按鈕綁定所對(duì)應(yīng)todoitem到表單進(jìn)行編輯
3、點(diǎn)擊表單中OK按鈕,對(duì)編輯結(jié)果進(jìn)行應(yīng)用。
注意:這里需要區(qū)分,在點(diǎn)擊OK按鈕時(shí),進(jìn)行的是新增操作還是編輯操作,我們對(duì)我們數(shù)據(jù)結(jié)構(gòu)加入自增ID來標(biāo)示,如果編輯項(xiàng)目有ID,則為保存編輯操作,如果不存在ID則為新增保存操作,對(duì)我們的數(shù)據(jù)結(jié)構(gòu)進(jìn)行以下微調(diào),由于新增了ID項(xiàng)目,那么在data屬性中也要增加ID屬性,這樣每次新增屬性都要直接修改data屬性,這就是變化點(diǎn),下面我們對(duì)變化點(diǎn)進(jìn)行簡單封裝,修改代碼如下:
data: { todolist: [], todoItem:{ id:'', title:'', desc:'' } },
另外我們需要實(shí)現(xiàn)自增ID,這里采用最直接的方式,全局ID,使其自增即可,對(duì)TodoItem進(jìn)行簡單的閉包處理:
var TodoItem = (function () { var id = 1; return function (title, desc) { this.title = title; this.desc = desc; this.id = id++; } })();
為了適應(yīng)新數(shù)據(jù)結(jié)構(gòu)的變化,則其它修改部分整體貼出來,變化部分見黃色:
<!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已經(jīng)完成,那么添加編輯時(shí)綁定,按照上面的步驟,先添加編輯按鈕,在刪除按鈕后添加編輯按鈕,并在methods對(duì)象中增加對(duì)應(yīng)的回調(diào)函數(shù),對(duì)edit操作進(jìn)行響應(yīng),函數(shù)中主要實(shí)現(xiàn)對(duì)todoItem對(duì)象進(jìn)行綁定操作,具體代碼修改如下:
<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值等于所傳參數(shù)的todoitem var obj = this.todolist.filter(v => v.id === id)[0]; //對(duì)數(shù)據(jù)進(jìn)行綁定,則數(shù)據(jù)會(huì)響應(yīng)到表單上 this.todoItem = obj; }, ...省略其它 }
這樣有沒有問題呢?我們運(yùn)行看一下效果:
從運(yùn)行結(jié)果上看,我們點(diǎn)擊edit操作,的確完成了綁定,但是在我們修改編輯,還沒有點(diǎn)擊OK按鈕的情況下,表單中的變化已經(jīng)提現(xiàn)到了列表中,這就不符合正常邏輯了,為什么會(huì)有這樣的情況呢,原因就在于this.todoItem=obj;這句代碼就是所謂的引用賦值,所以todoitem和obj指向的是同一個(gè)地址,則對(duì)this.todoItem的修改,會(huì)直接反應(yīng)到obj上,也就是todoList中的這個(gè)元素上,所以在列表中會(huì)直接提現(xiàn)出來,避免這種情況的發(fā)生的方法,只要避免飲用賦值即可,所以對(duì)上述代碼進(jìn)行如下修改:
//找到id值等于所傳參數(shù)的todoitem var obj = this.todolist.filter(v => v.id === id)[0]; //對(duì)數(shù)據(jù)進(jìn)行綁定,則數(shù)據(jù)會(huì)響應(yīng)到表單上 this.todoItem = { id:obj.id, title:obj.title, desc:obj.desc };
刷新運(yùn)行,發(fā)生程序按照預(yù)期運(yùn)行了,接下來,增加更新保存操作,修改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值等于所傳參數(shù)的todoitem var obj = this.todolist.filter(v => v.id === id)[0]; //對(duì)數(shù)據(jù)進(jìn)行綁定,則數(shù)據(jù)會(huì)響應(yīng)到表單上 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 ) ); } //重置表單 這部分筆誤,在實(shí)際代碼中已修改,但是貼上來的代碼沒有做修改,具體見最下面代碼,錯(cuò)誤原因見下方回復(fù) this.todoItem = {}; }, remove: function (index) { this.todolist.splice(index, 1); } }
代碼比較簡單,這里就不再贅述,可以看一下運(yùn)行效果:
為了逼格更高一點(diǎn),這里我再介紹一個(gè)指令,其實(shí)上面已經(jīng)使用了,v-bind ,這個(gè)指令和v-on是類似的,兩者的區(qū)別在于后面的參數(shù)不同,一般v-bind用來傳遞屬性參數(shù),一般使用縮寫形式:attr,可以綁定自定義屬性,上面代碼中我們對(duì)Id值的綁定已經(jīng)使用了v-bind:value="todoItem.id",這里相當(dāng)于angular中ng-bind?;趯?duì)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>
刷新運(yùn)行:
上面代碼能很好的運(yùn)行,但是現(xiàn)在如果我需要修改一下驗(yàn)證規(guī)則,在title和desc都不為空的情況下,才使用OK按鈕可用,如何做?你當(dāng)然會(huì)說,很簡單,直接加入一個(gè)&&條件不就行了,但是問題在于,現(xiàn)在我的模型比較小,屬性比較少,如果我存在一個(gè)大量屬性的對(duì)象,做類似的驗(yàn)證,這樣來修改代碼就是一個(gè)坑了,說到這里,其實(shí)已經(jīng)可以想到,既然驗(yàn)證規(guī)則再變,那么可以考慮作為一個(gè)變化點(diǎn)封裝起來,最直觀的方式,是封裝為一個(gè)方法,但是vue提供了更好的方式:computed,計(jì)算屬性,這個(gè)計(jì)算屬性應(yīng)該是來自于knockout的概念,有興趣的可以看一下knockout中計(jì)算屬性,修改代碼如下:
new Vue({ el: '#app', data: { todolist: [], todoItem: { id: '', title: '', desc: '' } }, computed:{ canSave:function(){ return !this.todoItem.title || !this.todoItem.desc; } }, ...省略其它 } })
可以看到computed屬性是以方法的方式來定義的,這里是最簡單方式,只讀的方式,當(dāng)然還可以通過get set方式進(jìn)行讀寫控制,我們后期的代碼中可能會(huì)見到,如果捉急,可以去查看官方文檔。在computed使用的時(shí)候,和方法調(diào)用截然不同,而是和data屬性中代理的模式一樣,如果你使用過knockout,那么你對(duì)這種用法就見怪不怪了,html部分修改如下:
<div class="form-inline"> <input type="button" value="OK" v-on:click="save()" class="btn btn-primary offset-md-10" :disabled='canSave'/> </div>
刷新頁面,運(yùn)行效果如圖:
ok,編輯這部分內(nèi)容就到這里吧,在沒有后端接口的前提下,保存操作都是模擬的,接下來對(duì)我們的查詢進(jìn)行一下簡單的介紹,這里查詢,由于沒有后端接口,咱們只做最簡單的演示,對(duì)代碼做如下處理:
1、增加查詢輸入框,keyword,添加查詢按鈕
2、點(diǎn)擊查詢操作,預(yù)期結(jié)果:根據(jù)輸入的查詢關(guān)鍵字,過濾列表
按照上面思路對(duì)我們代碼進(jìn)行修改:
<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屬性,以實(shí)現(xiàn)對(duì)輸入框的綁定,在methods中添加query方法:
//全局變量,用來緩存所有數(shù)據(jù) var list = []; data: { todolist: [], todoItem: { id: '', title: '', desc: '' }, keyword:'' },
query: function () { //過濾title中不包含keyword的數(shù)據(jù) //這里必須通過list全局變量過濾,而不能通過this.todolist,因?yàn)樾枰othis.todolist賦值,賦值后無法還原原來的列表。 this.todolist = list.filter(v => v.title.indexOf(this.keyword) !== -1); }
刷新頁面運(yùn)行效果如圖:
代碼部分注釋中已經(jīng)寫的很清楚了,有疑問可提價(jià)comment。本章就到這里,文章有點(diǎn)水,在(三)中會(huì)加入添加服務(wù)端支持,并使用axios和服務(wù)端rest接口進(jìn)行交互敬請(qǐng)期待,準(zhǔn)備睡覺。
<!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的數(shù)據(jù) //這里必須通過list全局變量過濾,而不能通過this.todolist,因?yàn)樾枰othis.todolist賦值,賦值后無法還原原來的列表。 this.todolist = list.filter(v => v.title.indexOf(this.keyword) !== -1); }, edit: function (id) { //找到id值等于所傳參數(shù)的todoitem var obj = this.todolist.filter(v => v.id === id)[0]; //對(duì)數(shù)據(jù)進(jìn)行綁定,則數(shù)據(jù)會(huì)響應(yīng)到表單上 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>
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- webpack學(xué)習(xí)教程之前端性能優(yōu)化總結(jié)
- 聊聊那些使用前端Javascript實(shí)現(xiàn)的機(jī)器學(xué)習(xí)類庫
- 前端主流框架vue學(xué)習(xí)筆記第一篇
- 前端框架學(xué)習(xí)總結(jié)之Angular、React與Vue的比較詳解
- 新手學(xué)習(xí)前端之js模仿淘寶主頁網(wǎng)站
- asp.net基礎(chǔ)學(xué)習(xí)之前端頁面布局
- 前端學(xué)習(xí)筆記style,currentStyle,getComputedStyle的用法與區(qū)別
- 0基礎(chǔ)學(xué)習(xí)前端開發(fā)的一些建議
相關(guān)文章
elementui中tabel組件的scope.$index的使用及說明
這篇文章主要介紹了elementui中tabel組件的scope.$index的使用及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10Vue項(xiàng)目配置、切換主題顏色詳細(xì)教程(mixin+scss方式,簡單高效)
這篇文章主要給大家介紹了關(guān)于Vue項(xiàng)目配置、切換主題顏色(mixin+scss方式)的相關(guān)資料,根據(jù)預(yù)設(shè)的配色方案,在前端實(shí)現(xiàn)動(dòng)態(tài)切換系統(tǒng)主題顏色,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11vant steps流程圖的圖標(biāo)使用slot自定義方式
這篇文章主要介紹了vant steps流程圖的圖標(biāo)使用slot自定義方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06vue-cli 項(xiàng)目打包完成后運(yùn)行文件路徑報(bào)錯(cuò)問題
這篇文章主要介紹了vue-cli 項(xiàng)目打包完成后運(yùn)行文件路徑報(bào)錯(cuò)問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07vue實(shí)現(xiàn)移動(dòng)端H5數(shù)字鍵盤組件使用詳解
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)移動(dòng)端H5數(shù)字鍵盤組件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08