大家好,這里是「 從零開始學 Web 系列教程 」,並在下列地址同步更新......
- github:https://github.com/Daotin/Web
- 微信公眾號:Web前端之巔
- 博客園:http://www.cnblogs.com/lvonve/
- CSDN:https://blog.csdn.net/lvonve/
在這里我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,期間也會分享一些好玩的項目。現在就讓我們一起進入 Web 前端學習的冒險之旅吧!
一、品牌管理案例
如下圖,
1、實現輸入id和name后,點擊add按鈕,添加到table中;
2、點擊數據的del,可以刪除這條數據。
代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./lib/vue-2.4.0.js"></script>
<style>
* {
padding: 0;
margin: 0;
position: relative;
}
/* 實現任意無寬高盒子居中顯示 */
#app {
position: absolute;
left: 50%;
top: 100px;
transform: translateX(-50%);
}
.box {
width: 500px;
height: 40px;
background-color: #ccc;
display: inline-block;
text-align: center;
line-height: 40px;
border: 1px solid #aaa;
box-sizing: border-box;
border-bottom: none;
}
.tb {
width: 500px;
text-align: center;
border-collapse: collapse;
border-color: #ccc;
}
</style>
</head>
<body>
<div id="app">
<div class="box">
<label for="id">
ID:
<input type="text" id="id" v-model="id">
</label>
<label for="name">
name:
<input type="text" id="name" v-model="name">
</label>
<input type="button" value="add" @click="addClick">
</div>
<table border="1" cellspacing="0" class="tb">
<tr v-for="item in list">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.ctime}}</td>
<td>
<!-- 綁定的事件是可以傳參數的,這里傳入需要刪除的對象id -->
<a href="javascript:;" @click.prevent="delClick(item.id)">del</a>
</td>
</tr>
</table>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
id: "",
name: "",
list: [{
id: 1,
name: 'tony',
ctime: new Date()
},
{
id: 2,
name: 'stark',
ctime: new Date()
}
]
},
methods: {
addClick() {
// 1.獲取表單數據
// 2.組織出一個對象
// 3.將對象添加到data中(不需要重新渲染頁面)
let item = {
id: this.id,
name: this.name,
ctime: new Date()
};
if ((this.id != "") && (this.name != "")) {
this.list.push(item);
}
// 4.最后將表單清空
this.id = this.name = "";
},
delClick(id) {
// 1.根據id找到索引(循環查找)
// 2.調用數組的 splice方法刪除
this.list.filter((item, index) => {
if (item.id == id) {
this.list.splice(index, 1);
return true;
}
});
}
}
});
</script>
</body>
</html>
注意:
1、事件名后面可以加括號(
@click="addClick"
等價於@click="addClick()
,這樣寫的話,就可以傳參。)
1、增加搜索需求
在Query中輸入字符串,如果name項中包括Query中的字符串,則顯示。
分析:
如果要滿足條件才顯示相關行,那么 <tr v-for="item in list">
中的list就是一個可變的。這里我們使用一個函數,函數里面進行判斷是否包含Query中的字符串,然后將包含的拷貝到新數組中,填充到list的位置:
<tr v-for="item in search(keywords)">
methods: {
addClick() {
//...
},
delClick(id) {
//...
},
// 添加的用於判斷的函數
search(keywords) {
// 定義新數組保存符合條件的項
let newList = [];
this.list.forEach((item, index) => {
// 包含則返回true
if (item.name.includes(keywords)) {
newList.push(item);
}
});
return newList;
}
}
全部源碼:
<!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>Document</title>
<script src="./lib/vue-2.4.0.js"></script>
<style>
* {
padding: 0;
margin: 0;
position: relative;
}
/* 實現任意無寬高盒子居中 */
#app {
position: absolute;
left: 50%;
top: 100px;
transform: translateX(-50%);
}
.box {
width: 800px;
height: 40px;
background-color: #ccc;
display: inline-block;
text-align: center;
line-height: 40px;
border: 1px solid #aaa;
box-sizing: border-box;
border-bottom: none;
}
.box>input[type="button"] {
width: 60px;
background-color: #aaa;
border: 0;
border: 1px solid #aaa;
}
.tb {
width: 800px;
text-align: center;
border-collapse: collapse;
border-color: #ccc;
}
</style>
</head>
<body>
<div id="app">
<div class="box">
<label for="id">
ID:
<input type="text" id="id" v-model="id">
</label>
<label for="name">
name:
<input type="text" id="name" v-model="name">
</label>
<input type="button" value="add" @click="addClick">
<label for="sel">
Query:
<input type="text" id="sel" v-model="keywords">
</label>
</div>
<table border="1" cellspacing="0" class="tb">
<!-- 有查詢的話,這里就不應該固定死,而是根據keywords動態生成新的數組 -->
<!-- <tr v-for="item in list"></tr> -->
<tr v-for="item in search(keywords)">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.ctime | ctimeFormat}}</td>
<td>
<!-- 綁定的事件是可以傳參數的,這里傳入需要刪除的對象id -->
<a href="javascript:;" @click.prevent="delClick(item.id)">del</a>
</td>
</tr>
</table>
</div>
<script>
// ctime 過濾器
Vue.filter('ctimeFormat', (data) => {
let time = new Date(data);
let year = time.getFullYear();
let month = (time.getMonth() + 1).toString().padStart(2, '0');
let day = (time.getDate()).toString().padStart(2, '0');
let hour = (time.getHours()).toString().padStart(2, '0');
let minute = (time.getMinutes()).toString().padStart(2, '0');
let second = (time.getSeconds()).toString().padStart(2, '0');
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
});
var vm = new Vue({
el: "#app",
data: {
id: "",
name: "",
keywords: "",
list: [{
id: 1,
name: 'tony',
ctime: new Date()
},
{
id: 2,
name: 'stark',
ctime: new Date()
}
]
},
methods: {
addClick() {
// 1.獲取表單數據
// 2.組織處一個對象
// 3.將對象添加到data中(不需要重新渲染頁面)
let item = {
id: this.id,
name: this.name,
ctime: new Date()
};
if ((this.id != "") && (this.name != "")) {
this.list.push(item);
}
// 4.最后將表單清空
this.id = this.name = "";
},
delClick(id) {
// 1.根據id找到索引(循環查找)
// 2.調用數組的 splice方法刪除
this.list.filter((item, index) => {
if (item.id == id) {
this.list.splice(index, 1);
return true;
}
});
},
search(keywords) {
// 定義新數組保存符合條件的項
let newList = [];
this.list.forEach((item, index) => {
// 包含則返回true
if (item.name.includes(keywords)) {
newList.push(item);
}
});
return newList;
}
}
});
</script>
</body>
</html>
二、過濾器
vue 允許自定義過濾器,可被用作一些常見的文本格式化。
過濾器只能用在兩個地方:插值表達式和 v-bind
表達式 。
1、全局過濾器
基本用法:
<body>
<div id="box">
<p>{{msg | msgFormat}}</p>
</div>
<script>
// 使用Vue.filter來定義一個過濾器:
// 第一個參數:過濾器函數名稱
// 第二個參數:過濾器函數體
// 過濾器的參數就是管道符的前面待處理的字符串。
Vue.filter('msgFormat', (data) => {
return data.replace("vue", "Daotin");
});
var vm = new Vue({
el: " #box ",
data: {
msg: "hello vue"
},
methods: {}
});
</script>
</body>
1、使用 Vue.filter(); 來定義一個過濾器。
2、第一個參數:過濾器函數名稱;第二個參數:過濾器函數體
3、過濾器的參數就是管道符的前面待處理的字符串。
插值表達式里的過濾器函數可以帶參數:
相應的,在 Vue.filter('msgFormat', (data, arg1,arg2,...) 中msgFormat 的參數從第二位開始放置。
可以帶多個參數。
<body>
<div id="box">
<p>{{msg | msgFormat('is a boy', 'and good')}}</p>
</div>
<script>
// 使用Vue.filter來定義一個過濾器:
// 第一個參數:過濾器函數名稱
// 第二個參數:過濾器函數體
// 過濾器的參數就是管道符的前面待處理的字符串。
Vue.filter('msgFormat', (data, arg1, arg2) => {
return data.replace("vue", "Daotin " + arg1 + arg2);
});
var vm = new Vue({
el: " #box ",
data: {
msg: "hello vue"
},
methods: {}
});
</script>
</body>
使用全局過濾器格式化品牌管理案例的 ctime:
<td>{{item.ctime | ctimeFormat}}</td>
...
// ctime 過濾器
Vue.filter('ctimeFormat', (data) => {
let time = new Date(data);
let year = time.getFullYear();
let month = time.getMonth() + 1;
let day = time.getDate();
let hour = time.getHours();
let minute = time.getMinutes();
return `${year}-${month}-${day} ${hour}:${minute}`;
});
2、私有過濾器
全局過濾器就是如果有多個vm實例的話,所有的VM實例都可以使用。
全局過濾器書寫在 script直接標簽下。
而私有過濾器書寫在VM對象中:
注意:過濾器的調用原則是就近原則,即先調用私有過濾器再調用全局過濾器。
padStart和padEnd
// ctime 過濾器
Vue.filter('ctimeFormat', (data) => {
let time = new Date(data);
let year = time.getFullYear();
let month = (time.getMonth() + 1).toString().padStart(2, '0');
let day = (time.getDate()).toString().padStart(2, '0');
let hour = (time.getHours()).toString().padStart(2, '0');
let minute = (time.getMinutes()).toString().padStart(2, '0');
let second = (time.getSeconds()).toString().padStart(2, '0');
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
});
使用ES6中的字符串新方法
String.prototype.padStart(maxLength, fillString='')
或String.prototype.padEnd(maxLength, fillString='')
來填充字符串;padStart:從開頭填充
padEnd:從結尾填充
maxLength:填充后最大的長度
fillString:需要填充的字符串(fillString='',不填則以空字符填充)
三、按鍵修飾符
我們現在有個需求就是輸入ID和name后不點擊add按鈕,而是按下回車鍵也需要添加到列表中。
我們可以在name輸入框中加入按鍵抬起事件,並且指定是enter鍵抬起時才觸發。
<label for="name">
name:
<input type="text" id="name" v-model="name" @keyup.enter="addClick">
.enter
: 就是按鍵修飾符。
系統提供的按鍵修飾符有:
.enter
.tab
.delete
(捕獲“刪除”和“退格”鍵).esc
.space
.up
.down
.left
.right
如果我們想自定義其他的按鍵怎么辦呢?
通過Vue.config.keyCodes.f2 = 113;
;可以將f2作為按鍵修飾符添加到系統按鍵修飾符中。
具體每個按鍵的值是多少?下面是常見的按鍵的碼。
keyCode 8 = BackSpace BackSpace
keyCode 9 = Tab Tab
keyCode 12 = Clear
keyCode 13 = Enter
keyCode 16 = Shift_L
keyCode 17 = Control_L
keyCode 18 = Alt_L
keyCode 19 = Pause
keyCode 20 = Caps_Lock
keyCode 27 = Escape Escape
keyCode 32 = space
keyCode 33 = Prior
keyCode 34 = Next
keyCode 35 = End
keyCode 36 = Home
keyCode 37 = Left
keyCode 38 = Up
keyCode 39 = Right
keyCode 40 = Down
keyCode 41 = Select
keyCode 42 = Print
keyCode 43 = Execute
keyCode 45 = Insert
keyCode 46 = Delete
keyCode 47 = Help
keyCode 48 = 0 equal braceright
keyCode 49 = 1 exclam onesuperior
keyCode 50 = 2 quotedbl twosuperior
keyCode 51 = 3 section threesuperior
keyCode 52 = 4 dollar
keyCode 53 = 5 percent
keyCode 54 = 6 ampersand
keyCode 55 = 7 slash braceleft
keyCode 56 = 8 parenleft bracketleft
keyCode 57 = 9 parenright bracketright
keyCode 65 = a A
keyCode 66 = b B
keyCode 67 = c C
keyCode 68 = d D
keyCode 69 = e E EuroSign
keyCode 70 = f F
keyCode 71 = g G
keyCode 72 = h H
keyCode 73 = i I
keyCode 74 = j J
keyCode 75 = k K
keyCode 76 = l L
keyCode 77 = m M mu
keyCode 78 = n N
keyCode 79 = o O
keyCode 80 = p P
keyCode 81 = q Q at
keyCode 82 = r R
keyCode 83 = s S
keyCode 84 = t T
keyCode 85 = u U
keyCode 86 = v V
keyCode 87 = w W
keyCode 88 = x X
keyCode 89 = y Y
keyCode 90 = z Z
keyCode 96 = KP_0 KP_0
keyCode 97 = KP_1 KP_1
keyCode 98 = KP_2 KP_2
keyCode 99 = KP_3 KP_3
keyCode 100 = KP_4 KP_4
keyCode 101 = KP_5 KP_5
keyCode 102 = KP_6 KP_6
keyCode 103 = KP_7 KP_7
keyCode 104 = KP_8 KP_8
keyCode 105 = KP_9 KP_9
keyCode 106 = KP_Multiply KP_Multiply
keyCode 107 = KP_Add KP_Add
keyCode 108 = KP_Separator KP_Separator
keyCode 109 = KP_Subtract KP_Subtract
keyCode 110 = KP_Decimal KP_Decimal
keyCode 111 = KP_Divide KP_Divide
keyCode 112 = F1
keyCode 113 = F2
keyCode 114 = F3
keyCode 115 = F4
keyCode 116 = F5
keyCode 117 = F6
keyCode 118 = F7
keyCode 119 = F8
keyCode 120 = F9
keyCode 121 = F10
keyCode 122 = F11
keyCode 123 = F12
keyCode 124 = F13
keyCode 125 = F14
keyCode 126 = F15
keyCode 127 = F16
keyCode 128 = F17
keyCode 129 = F18
keyCode 130 = F19
keyCode 131 = F20
keyCode 132 = F21
keyCode 133 = F22
keyCode 134 = F23
keyCode 135 = F24
示例:
<input type="text" id="name" v-model="name" @keyup.f2="addClick">
//...
<script>
Vue.config.keyCodes.f2 = 113;
</script>
四、自定義指令
除了核心功能默認內置的指令 (v-model
等),Vue 也允許注冊自定義指令。自定義指令是以 v-
開頭的指令。
比如我們想讓品牌管理案例中,在剛進入頁面的時候,就獲取 Query輸入框的焦點,但是vue並沒有提供這樣的指令。
之前我們可以通過獲取DOM元素,然后使用 DOM元素.focus();
方法來獲取焦點。但是在vue里面不推薦獲取DOM元素的方式。這時我們可以使用自定義指令的方式來達到獲取焦點。
比如:我們想定義一個v-focus
的指令來獲取焦點。
<label for="sel">
Query:
<input type="text" id="sel" v-model="keywords" v-focus>
</label>
<script>
// 自定義全局指令 v-focus,為綁定的元素自動獲取焦點:
Vue.directive('focus', {
inserted: function (el) { // inserted 表示被綁定元素插入父節點時調用
el.focus();
}
});
</script>
1、定義自定義指令的時候,不需要加
v-
,使用的時候需要加。2、注意: 在每個 函數中,第一個參數,永遠是
el
,表示 被綁定了指令的那個元素,這個 el 參數,是一個原生的JS對象。3、和JS行為有關的操作,最好在
inserted
中去執行
1、鈎子函數
inserted 是鈎子函數,類似的鈎子函數還有幾個,但是應用場景不同:
inserted
:被綁定元素插入DOM元素時調用一次(從內存渲染到頁面時如果綁定了 inserted 就執行)。bind
:只調用一次,指令第一次綁定到元素時調用。在這里可以進行一次性的初始化設置(在代碼加載到內存中的時候,如果綁定了bind就執行,比如樣式style的設定,使用bind綁定)。update
:所在組件的 VNode 更新時調用,但是可能發生在其子 VNode 更新之前。指令的值可能發生了改變,也可能沒有。
總結:一般:
1、與JS行為相關的操作在inserted中執行;
2、與樣式相關的在bind中執行。
2、鈎子函數參數
指令鈎子函數會被傳入以下參數:
el
:指令所綁定的元素,可以用來直接操作 DOM 。binding
:一個對象,包含以下屬性:name
:指令名,不包括v-
前綴。value
:指令的綁定值,例如:v-my-directive="1 + 1"
中,綁定值為2
。expression
:字符串形式的指令表達式。例如v-my-directive="1 + 1"
中,表達式為"1 + 1"
。- ...
- ...
我們可以為自定義指令賦值,比如我們想給Query文本框的字體顏色賦值:
<label for="sel">
Query:
<input type="text" id="sel" v-model="keywords" v-focus v-color="'red'">
</label>
之所以使用
v-color="'red'"
,而不是v-color="red"
,是因為如果是red字符串的話,就當做變量在vue的data中查找,而這里要表達的是字符串red。
自定義v-color指令:
Vue.directive("color", {
bind(el, binding) {
el.style.color = binding.value;
}
});
binding:這個名稱可以隨意。
3、自定義私有指令
自定義私有指令就是在vm實例中加入 directives
屬性,它是一個對象,其中屬性為自定義指令的名稱(不加 v-),值也是一個對象,對象里面是鈎子函數列表。
var vm = new Vue({
el: "#app",
data: {
//...
},
methods: {
//...
},
directives: {
"color": {
bind(el, binding) {
el.style.color = binding.value;
}
}
}
});
4、自定義指令的簡寫
我們之前都是在自定義指令名稱的后面跟上一個對象,里面寫上 bind,inserted,update的鈎子函數列表。
現在簡寫的話,就不需要跟上一個對象了:
directives: {
"color": (el, binding) => {
el.style.color = binding.value;
}
}
自定義名稱后可以直接跟上一個匿名函數,這個匿名函數就相當於bind和update的鈎子函數集合。所以,如果你只需要在bind或者update中進行元素的設置的話,就可以用這種簡寫的方式,當然如果是inserted的話,還是要寫回對象的方式。