前端主流框架vue學習筆記第二篇
接上篇,在本篇中,我們將要實現(xiàn)如下,功能,編輯和查詢,我們當前的todolist程序,和線上其它的demo程序不同,我們會對其進行增刪改查的基本操作,之后進行進一步的完善,按照常規(guī)的系統(tǒng)使用經驗,一般我們新增和編輯都是在模態(tài)框中處理,這里我們不會去構建復雜的模態(tài)框,只用一個簡單的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按鈕,對編輯結果進行應用。
注意:這里需要區(qū)分,在點擊OK按鈕時,進行的是新增操作還是編輯操作,我們對我們數(shù)據(jù)結構加入自增ID來標示,如果編輯項目有ID,則為保存編輯操作,如果不存在ID則為新增保存操作,對我們的數(shù)據(jù)結構進行以下微調,由于新增了ID項目,那么在data屬性中也要增加ID屬性,這樣每次新增屬性都要直接修改data屬性,這就是變化點,下面我們對變化點進行簡單封裝,修改代碼如下:
data: {
todolist: [],
todoItem:{
id:'',
title:'',
desc:''
}
},
另外我們需要實現(xiàn)自增ID,這里采用最直接的方式,全局ID,使其自增即可,對TodoItem進行簡單的閉包處理:
var TodoItem = (function () {
var id = 1;
return function (title, desc) {
this.title = title;
this.desc = desc;
this.id = id++;
}
})();
為了適應新數(shù)據(jù)結構的變化,則其它修改部分整體貼出來,變化部分見黃色:
<!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對象中增加對應的回調函數(shù),對edit操作進行響應,函數(shù)中主要實現(xiàn)對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值等于所傳參數(shù)的todoitem
var obj = this.todolist.filter(v => v.id === id)[0];
//對數(shù)據(jù)進行綁定,則數(shù)據(jù)會響應到表單上
this.todoItem = obj;
},
...省略其它
}
這樣有沒有問題呢?我們運行看一下效果:

從運行結果上看,我們點擊edit操作,的確完成了綁定,但是在我們修改編輯,還沒有點擊OK按鈕的情況下,表單中的變化已經提現(xiàn)到了列表中,這就不符合正常邏輯了,為什么會有這樣的情況呢,原因就在于this.todoItem=obj;這句代碼就是所謂的引用賦值,所以todoitem和obj指向的是同一個地址,則對this.todoItem的修改,會直接反應到obj上,也就是todoList中的這個元素上,所以在列表中會直接提現(xiàn)出來,避免這種情況的發(fā)生的方法,只要避免飲用賦值即可,所以對上述代碼進行如下修改:
//找到id值等于所傳參數(shù)的todoitem
var obj = this.todolist.filter(v => v.id === id)[0];
//對數(shù)據(jù)進行綁定,則數(shù)據(jù)會響應到表單上
this.todoItem = {
id:obj.id,
title:obj.title,
desc:obj.desc
};
刷新運行,發(fā)生程序按照預期運行了,接下來,增加更新保存操作,修改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];
//對數(shù)據(jù)進行綁定,則數(shù)據(jù)會響應到表單上
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是類似的,兩者的區(qū)別在于后面的參數(shù)不同,一般v-bind用來傳遞屬性參數(shù),一般使用縮寫形式:attr,可以綁定自定義屬性,上面代碼中我們對Id值的綁定已經使用了v-bind:value="todoItem.id",這里相當于angular中ng-bind?;趯-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>
刷新運行:

上面代碼能很好的運行,但是現(xiàn)在如果我需要修改一下驗證規(guī)則,在title和desc都不為空的情況下,才使用OK按鈕可用,如何做?你當然會說,很簡單,直接加入一個&&條件不就行了,但是問題在于,現(xiàn)在我的模型比較小,屬性比較少,如果我存在一個大量屬性的對象,做類似的驗證,這樣來修改代碼就是一個坑了,說到這里,其實已經可以想到,既然驗證規(guī)則再變,那么可以考慮作為一個變化點封裝起來,最直觀的方式,是封裝為一個方法,但是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、點擊查詢操作,預期結果:根據(jù)輸入的查詢關鍵字,過濾列表
按照上面思路對我們代碼進行修改:
<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屬性,以實現(xiàn)對輸入框的綁定,在methods中添加query方法:
//全局變量,用來緩存所有數(shù)據(jù)
var list = [];
data: {
todolist: [],
todoItem: {
id: '',
title: '',
desc: ''
},
keyword:''
},
query: function () {
//過濾title中不包含keyword的數(shù)據(jù)
//這里必須通過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的數(shù)據(jù)
//這里必須通過list全局變量過濾,而不能通過this.todolist,因為需要給this.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];
//對數(shù)據(jù)進行綁定,則數(shù)據(jù)會響應到表單上
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>
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
nuxt框架中對vuex進行模塊化設置的實現(xiàn)方法
這篇文章主要介紹了nuxt框架中對vuex進行模塊化設置的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-09-09
Vue3+echarts5踩坑以及resize方法報錯的解決
這篇文章主要介紹了Vue3+echarts5踩坑以及resize方法報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07
Vue2.0父組件與子組件之間的事件發(fā)射與接收實例代碼
這篇文章主要介紹了Vue2.0父組件與子組件之間的事件發(fā)射與接收實例代碼,需要的朋友可以參考下2017-09-09
vue實現(xiàn)點擊導航欄滾動頁面到指定位置的功能(推薦)
這篇文章主要介紹了vue實現(xiàn)點擊導航欄滾動頁面到指定位置的功能(推薦),步驟一是是通過獲取不同板塊的滾輪高度,步驟二通過編寫執(zhí)行滾動操作的函數(shù),結合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2023-11-11
Vue Getters和mapGetters的原理及使用示例詳解
Vuex的核心概念包括state、mutations、actions、getters和modules,今天,我們要深入探討其中一個關鍵部分:getters,以及它的相關輔助函數(shù)mapGetters,感興趣的朋友跟隨小編一起看看吧2024-08-08

