# 內置指令
>[success] 可在此處查看運行文檔中的代碼示例結果:[https://github.com/jianyaoo/Vue](https://github.com/jianyaoo/Vue)
[toc]
> 什么是指令?指令是指在Vue中帶有`v-`前綴的特殊html屬性。這些屬性綁定了一個表達式,并將這些特性應用到dom上。
## 基礎指令
基礎指令指不需要表達式的基本簡單指令,主要包括`v-cloack`和`v-once`指令
### v-cloak
v-cloak指令一般配合style樣式使用,在vue實例編譯結束后自動消失。一般配合dispaly:none使用用來避免頁面渲染的閃動。
>[success] 小提示:一般什么情況會導致頁面閃動?網絡較慢、數據量較大時,vue.js還沒有完全加載完而已經渲染了頁面會導致頁面閃動。
### v-once
v-once指令表示當前元素只渲染一次,包括當前元素及元素的所有子節點。即當元素首次渲染完畢后,數據不會再發生變化。一般用于渲染靜態內容。
```html
<div id="app">
<h3>01 - v-cloak</h3>
<span v-cloak>{{message}}</span>
<div v-cloak>
<span>{{message}}</span>
</div>
<h3>02 - v-once</h3>
<span v-once>{{message}}</span>
<div v-once>
<span>{{message}}</span>
</div>
<button @click="handle">修改message信息</button>
</div>
```
<p class="run">
運行結果:點擊按鈕時,只有上面的元素內容發生了改變,而v-once標題下的元素內容并未發生改變
</p>
## 條件渲染指令
條件渲染指令是指根據既定的條件來編譯元素或者顯示隱藏元素。主要分為`v-if`、`v-else-if`、`v-else`、`v-show`四個指令。
### v-if、v-else-if、v-else
v-if指令一般配合v-esle指令使用,當v-if指令后的表達式為true時編譯當前元素,否則的話編譯v-else指令上的元素。在vue2.1之后新增了v-else-if指令,該指令只能緊跟v-if指令使用。
**<span style="padding-top:15px;display:inline-block;">代碼示例</span>**
```html
<h3>v-if / v-else-if / v-else</h3>
<p v-if="status === 1">當前是第一種工作類型</p>
<p v-else-if="status === 2">當前是第二種工作類型</p>
<p v-else="status === 3">當前是第三種工作類型</p>
<button @click="changeStatus">切換狀態</button>
```
```javaScript
changeStatus:function () {
this.status = (this.status - 1 === 0 ? 3 : this.status - 1);
}
```
<p class="run">
運行結果:點擊按鈕,依次顯示當前三種工作類型。點擊控制臺可以查看到只有顯示的元素進行了編譯而其他兩條元素并沒有進行編譯。
</p>
### v-show
v-show指令與v-if指令的渲染方式不同,v-show指令是在初始時就編譯完所有的元素,通過給元素添加`display:none`的方式控制元素的顯示和隱藏。
~~~html
<h3>v-show</h3>
<p v-show="isShow === true">你能看見我</p>
<button @click="changeShow">切換show的狀態</button>
~~~
~~~JavaScript
changeShow:function () {
this.isShow = (this.isShow === true ? false : true);
}
~~~
<p class="run">
運行結果:通過點擊按鈕,切換元素的隱藏與顯示,通過控制臺可查看當元素不可見時在頁面中也是渲染了當前元素,只是添加了`display:none`的屬性控制隱藏。
</p>
### v-if指令的特性
**<span style="padding-top:15px;display:inline-block;">多元素控制</span>**
當一條指令需要控制多條元素時,可將指令添加在標簽`template`中,最后的渲染結果不會渲染該元素。
**<span style="padding-top:15px;display:inline-block;">元素復用性</span>**
v-if元素具有元素復用性,即當切換元素后如果元素類型沒有改變只是屬性發生改變則會復用該元素而只是修改發生變化的部分。解決元素的復用性可在不啟用復用元素上添加key屬性且key值不同。
代碼示例
~~~html
<template v-if="form === 'name'">
<label>請輸入姓名:</label>
<input type="text" placeholder="請輸入姓名" key="name">
</template>
<template v-else="form === 'email'">
<label>請輸入郵箱:</label>
<input type="text" placeholder="請輸入郵箱" key="email">
</template>
~~~
~~~JavaScript
changeForm:function () {
this.form = (this.form == "name" ? "email" :"name");
},
~~~
<p class="run">
運行結果:點擊按鈕切換不同的登錄狀態。<br />
代碼解析:當需要控制多個元素時如上所示添加template標簽控制。當在輸入框中輸入內容后切換狀態,輸入框中的內容依舊還在只是placeholder等屬性發生了改變,說明input框被復用了只是修改了屬性值。在input上添加不同的key值后再次切換,輸入框內的內容被清空,說明input框被重新編譯。
</p>
### v-if和v-show的對比
v-if指令具有懶惰性,在初始化時如果不滿足條件則就不會進行編譯,直到第一次滿足后在進行編譯,但是在切換時會重新編譯元素,所以在切換狀態時具有很大的開銷
v-show指令在初始化時需要編譯全部的html元素,所以在初始化時具有很大的想開銷。
如果項目需要經常切換元素,宜使用`v-show`指令,如果運行時條件不經常改變則使用`v-if`更好。
## 列表渲染指令 v-for
`v-for`是指循環渲染指令,通過使用`v-for`指令,將一個數組渲染成一組元素。使用語法:
```
<span v-for="item in items"></span>
```
其中,items表示數組,item是每一個數組值得別名,用于循環。
### 基本使用
**<span style="padding-top:15px;display:inline-block;">使用數組渲染一組元素</span>**
```html
<ul>
<li v-for="book in books"> {{book}}</li>
</ul>
```
```JavaScript
data:{
books:["高數","英文","語文"],
},
```
<div class="run">
執行結果:
<ul>
<li>高數</li>
<li>英文</li>
<li>語文</li>
</ul>
</div>
**<span style="padding-top:30px;display:inline-block;">添加位置索引</span>**
```html
<ul>
<li v-for="(book , index) in books"> {{index}} - {{book}}</li>
</ul>
```
```JavaScript
data:{
books:["高數","英文","語文"],
},
```
<div class="run">
執行結果:
<ul>
<li>0 - 高數</li>
<li>1 - 英文</li>
<li>2 - 語文</li>
</ul>
</div>
>[info] 可以獲取到當前值在數組中的位置,即在別名之后添加一個index的變量。別名和位置使用括號括起來。
**<span style="padding-top:30px;display:inline-block;">直接使用數字</span>**
~~~
<span v-for="n in 10">{{n}}</span>
~~~
<div class="run">
執行結果:
<span>12345678910</span>
</div>
**<span style="padding-top:30px;display:inline-block;">使用對象循環渲染</span>**
```
<ul >
<li v-for="(item , name , index) in items">{{index}} : {{name}} = {{item}}</li>
</ul>
```
~~~JavaScript
items:{
title:"vue實戰",
name:"云之遙",
year:"2019年"
},
~~~
<div class="run">
執行結果:
<ul>
<li>0 : title = Vue實戰</li>
<li>1 : name = 云之遙</li>
<li>2:yera = 2019年</li>
</ul>
</div>
**<span style="padding-top:30px;display:inline-block;">一次渲染多個元素</span>**
```html
<template v-for="bookInfo in bookInfos">
<span>{{bookInfo.name}}</span>
<span>{{bookInfo.author}}</span>
</template>
```
```javaScript
bookInfos:[
{name:"高數",author:"lili"},
{name:"英語",author:"July"},
{name:"語文",author:"之遙"}
]
```
<div class="run">
執行結果:
<span>高數</span><span>lili</span>
<span>英語</span><span>July</span>
<span>語文</span><span>之遙</span>
</div>
### 數組更新檢測
對數組的操作方法分為**變異方法**和**非變異方法**,變異方法即使數組本身發生改變,從而影響了視圖更新。
**<span style="padding-top:30px;display:inline-block;">變異方法</span>**
>[info] 變異方法即直接影響數組本身的方法,Vue將變異方法進行了包裹,所以變異方法會直接影響視圖變化。
* `push()` // 在原數組的最后追加一個值
* `pop()` // 將原數組截取掉最后一個值
* `shift()` // 截取掉原數組的第一個值
* `unshift()` // 在原數組前添加值
* `splice()` // 截取數組
* `sort()` // 對數組進行排序
* `reverse()` // 對數組進行反轉
代碼實例
~~~html
<p>變異方法</p>
<ul>
<li v-for="book in books">{{book}}</li>
</ul>
<button @click="handleBooks(1)">添加數組</button>
<button @click="handleBooks(2)">刪除數組</button>
<button @click="handleBooks(3)">shift</button>
<button @click="handleBooks(4)">unshift</button>
<button @click="handleBooks(5)">sort</button>
<button @click="handleBooks(6)">reverse</button>
~~~
~~~JavaScript
handleBooks:function (index) {
switch (index) {
case 1 :
this.books.push("物理");
break;
case 2 :
this.books.pop();
break;
case 3 :
this.books.shift();
break;
case 4 :
this.books.unshift("生物","化學","計算機");
break;
case 5:
this.books.sort();
break;
case 6 :
this.books.reverse();
break;
}
},
~~~
<div class="run">
<p>執行結果:</p>
<p>點擊添加數組界面顯示:【高數、英文、語文、物理】</p>
<p>接續點擊刪除數組界面顯示:【高數、英文、語文】</p>
<p>接續點擊shift界面顯示:【英文、語文】</p>
<p>接續點擊unshift界面顯示:【生物、化學、計算機、英文、語文】</p>
<p>接續點擊sort界面顯示:【化學、生物、英語、計算機、語文】</p>
<p>接續點擊reverse界面顯示:【語文、計算機、英語、生物、化學】</p>
</div>
**<span style="padding-top:30px;display:inline-block;">非變異方法</span>**
>[info] 非變異方法即使用方法后會放回一個新的數組,但是不會改變原數組。所以非變異方法直接使用后不會更新視圖顯示。
* `filter()` // 數組過濾函數
* `concat()` // 數組拼接函數
* `slice()` // 數組截取函數
代碼實例
~~~html
<p>替換方法</p>
<ul>
<li v-for="array in arrays">{{array.message}}</li>
</ul>
<button @click="handleEvent(1)">filter</button>
<button @click="handleEvent(2)">concat</button>
<button @click="handleEvent(3)">slice</button>
~~~
~~~JavaScript
data:{
arrays:[
{ message:"Foo" },
{ message:"Bar" }
],
},
handleEvent:function (index) {
switch(index){
case 1:
this.arrays = this.arrays.filter(function (item) {
return item.message.match(/Foo/);
})
break;
case 2:
var concatStr = [{
message:"line"
}]
this.arrays = this.arrays.concat(concatStr);
break;
case 3:
this.arrays = this.arrays.slice(1);
break;
}
},
~~~
<div class="run">
<p>執行結果:</p>
<p>點擊filter界面顯示:【Foo】</p>
<p>接續點擊concat界面顯示:【Foo、line】</p>
<p>接續點擊slice界面顯示:【line】</p>
</div>
>[success] 小提示:非變異方法不會改變原數組的值,所以不會響應視圖。如果在開發中使用非變異方法且要響應視圖,可以使用新數組替換掉舊數組。在Vue中為了使元素最大化的實現復用啟用了一些智能方式,所以使用含有相同元素的數組去替換掉舊數組也是比較高效的一種操作。
### 數組變更注意事項
變更注意事項指要<span style="color:red"> 特別注意以下兩點不會導致視圖響應。</span>
* 第一種:通過索引值直接改變數組的值
* 第二種:通過length直接改變數組的長度
**<span style="padding-top:30px;display:inline-block;">問題展示</span>**
```JavaScript
var arr = ["Foo","Ban"];
arr[1] = "Line"; // 不會觸發響應
arr.length = 1; // 不會觸發反應
```
**<span style="padding-top:20px;display:inline-block;">解決方式</span>**
```
// 解決第一種問題可以使用下面兩種方式
Vue.set(this.arr , 1 , "Line");
this.arr.splice(2,1,"Line");
// 解決第二種問題直接使用splice變異函數
this.arr.splice(newLength);
```
>[info] 關于解決方式:使用Vue的set方法,該方法接收三個參數(數組 , 位置 , 新值);也可以使用splice等變異函數。本質上就是改變數組的值。
**<span style="padding-top:20px;display:inline-block;">代碼示例</span>**
~~~html
<p>注意事項</p>
<ul>
<li v-for="book in books">{{book}}</li>
</ul>
<button @click="changeIndex">注意事項1</button>
<button @click="changeIndex1">解決方法</button>
~~~
~~~JavaScript
data:{
books:["高數","英文","語文"],
type:1
}
changeIndex:function () {
this.books[2] = "編譯原理"
},
changeIndex1:function () {
if(this.type === 1){
this.books.splice(2 , 1 , "編譯原理");
this.type = 2;
}else if (this.type === 2){
Vue.set(this.books , 2 , "操作系統");
this.type = 3;
}else if (this.type === 3){
this.$set(this.books , 2 ,"數字電路");
this.type =1;
}
},
~~~
<div class="run">
<p>執行結果:</p>
<p>點擊注意事項1按鈕頁面無反應,不會改變數組值</p>
<p>接續點擊解決方式按鈕界面發生改變,以三種不同的方式修改數組值都可以發生改變</p>
</div>
### 對象變更注意事項
對象變更注意事項和數組變更事項類似,動態添加、修改、刪除對象的屬性都不會導致視圖響應。
**<span style="padding-top:20px;display:inline-block;">問題展示</span>**
```
this.items.age = "27"; //該語句不會在視同發生改變
```
**<span style="padding-top:20px;display:inline-block;">解決方式</span>**
* 第一種:使用Vue.set(projectName , key值 , value值)函數
* 第二種:使用實例方法 vm.$set()
**<span style="padding-top:20px;display:inline-block;">代碼實例</span>**
~~~html
<ul>
<li v-for="(item , name) in items">{{name}} - {{item}}</li>
</ul>
<button @click="changeKey">注意事項1</button>
<button @click="changeKey1">解決方法</button>
~~~
~~~
data:{
items:{
title:"vue實戰",
name:"云之遙",
year:"2019年"
},
}
changeKey:function () {
this.items.age = "27";
},
changeKey1:function () {
if (this.type ===1 ){
Vue.set(this.items , "age" , "27");
this.type = 2;
}else if (this.type === 2){
this.items = Object.assign({} , this.items , {
age:27,
area:"北京"
})
}
}
~~~
<div class="run">
<p>執行結果:</p>
<p>點擊注意事項1按鈕頁面無反應,不會改變數組值</p>
<p>接續點擊解決方式按鈕界面發生改變,以兩種不同的方式修改數組值都可以發生改變</p>
</div>
### v-for與v-if
>[danger] 官方文檔提示:一般**不**建議在同一個元素上同時使用v-for和v-if
當一個元素上同時含有`v-for`指令和`v-if`指令時,`v-for`指令的優先級高于`v-if`.會先執行循環,然后在每個循環里進行判斷。如果有這種需求可以這樣使用。
**<span style="padding-top:20px;display:inline-block;">代碼實例</span>**
~~~html
<p>v-if和v-for</p>
<ul>
<li v-for="(todo , index) in todoList" v-if="!todo.isDone">{{index}} - {{todo.event}}</li>
</ul>
~~~
~~~
todoList:[
{ event:"事件1" , isDone:true },
{ event:"事件2" , isDone:false },
{ event:"事件3" , isDone:false },
{ event:"事件4" , isDone:true },
]
~~~
<div class="run">
<p>執行結果:</p>
<ul><!----><li>1 - 事件2</li><li>2 - 事件3</li><!----></ul>
</div>
## 方法與事件指令
>[info] 方法與事件指令 `v-on`指令,語法糖簡寫為@
### v-on指令的基本使用
**<span style="padding-top:20px;display:inline-block;">五種使用方法</span>**
* 直接在指令后寫表達式
* 使用函數名稱
* 使用無參函數名
* 使用傳參函數名
* 使用傳參函數且使用原生事件
**<span style="padding-top:20px;display:inline-block;">代碼實例</span>**
```html
<h3>v-on指定的基本使用</h3>
<span>點擊次數:{{count}}</span><br />
<button @click="count++">表達式</button>
<button @click="addCount1">直接調用</button>
<button @click="addCount3()">含()調用</button>
<button @click="addCount3(10)">傳參調用</button>
<a @click="addCount4(10 , $event)" href="https://www.baidu.com/">event參數</a>
```
~~~JavaScript
addCount1:function () {
this.count ++ ;
},
addCount3:function (param) {
param = param || 1 ;
this.count += param;
},
addCount4:function (param , event) {
event.preventDefault();
this.count += param;
},
~~~
**<span style="padding-top:20px;display:inline-block;">重點說明</span>**
1. 在html中直接寫表達式的方式不便于代碼維護且只適用于簡單邏輯,所以日常開發中很少會使用第一種模式。
2. <div style="background:#fdf7f7;color:?#d9534f;border:1px solid #d9534f;padding:3px 10px">第二種直接調用和第三種含括號調用的方式不同,直接調用默認表示傳遞了一個原生事件參數,所以如果使用直接調用的方式執行`addCount3`時,param不會undefined,而是一個事件對象</div>
3. 如果在使用參數的同時還需要接受一個原生的事件對象,vue提供了$event 參數,**說明:$event參數必須要放在參數的最后一個**。
### 事件修飾符
>[info] 在事件處理程序中調用`event.preventDefault()`或`event.stopPropagation()`是非常常見的需求。盡管我們可以在方法中輕松實現這點,但更好的方式是:方法只有純粹的數據邏輯,而不是去處理 DOM 事件細節。而事件修飾符的存在就是為了解決這一問題。
>
**<span style="padding-top:20px;display:inline-block;">常用修飾符</span>**
* `.stop`
* `.prevent`
* `.capture`
* `.self`
* `.once`
**<span style="padding-top:20px;display:inline-block;">修飾符各個含義</span>**
`.prevent`:阻止元素的默認事件發生,即阻止a標簽的自動跳轉事件、submit的自動提交事件等等默認事件。
`.stop`:阻止冒泡事件發生
`.capture`:修改冒泡事件的觸發順序
`.self`:不對子元素的事件所觸發
`.once`:當前點擊事件只觸發一次
**<span style="padding-top:20px;display:inline-block;">代碼實例說明</span>**
~~~html
<h3>事件修飾符</h3>
<div @click="eventClick">
<div @click="eventClick1">
<a href="https://www.baidu.com/" @click="eventClick2">點擊我</a>
</div>
</div>
~~~
~~~javascript
eventClick:function () {
console.log("eventClick事件");
},
eventClick1:function () {
console.log("eventClick1事件");
},
eventClick2:function () {
console.log("eventClick2事件");
}
~~~
<div class="run">
<p>執行結果:</p>
<p>1、默認執行結果:eventClick2事件、eventClick1事件、eventClick事件,之后跳轉百度首頁</p>
<p>2、.stop:eventClick2事件,之后跳轉百度首頁</p>
<p>3、.prevent:eventClick2事件、eventClick1事件、eventClick事件,不跳轉百度首頁</p>
<p>4、.prevent:eventClick事件、eventClick1事件、eventClick2事件,跳轉百度首頁</p>
</div>
**<span style="padding-top:20px;display:inline-block;">修飾符更多詳情鏈接</span>**
[https://blog.csdn.net/qq\_37468455/article/details/95175054](https://blog.csdn.net/qq_37468455/article/details/95175054)
### 按鍵修飾符
**<span style="padding-top:20px;display:inline-block;">常用的按鍵修飾符</span>**
* `.enter`
* `.tab`
* `.delete`(捕獲“刪除”和“退格”鍵)
* `.esc`
* `.space`
* `.up`
* `.down`
* `.left`
* `.right`
### 系統修飾鍵
* `.ctrl`
* `.alt`
* `.shift`
* `.meta`
### 在HTML中監聽事件的解讀
1. 掃一眼 HTML 模板便能輕松定位在 JavaScript 代碼里對應的方法。
2. 無須在 JavaScript 里手動綁定事件,你的 ViewModel 代碼可以是非常純粹的邏輯,和 DOM 完全解耦,更易于測試。
3. 當一個 ViewModel 被銷毀時,所有的事件處理器都會自動被刪除。你無須擔心如何清理它們。