5.指令
什么是指令?
指令 (Directives) 是帶有 v-
前綴的特殊特性。指令特性的預期值是:單個 JavaScript 表達式。指令的職責是,當表達式的值改變時,將其產生的連帶影響,響應式地作用於 DOM。
例如我們在入門案例中的v-on,代表綁定事件。
5.1.插值表達式
5.1.1.花括號
格式:
{{表達式}}
說明:
- 該表達式支持JS語法,可以調用js內置函數(必須有返回值)
- 表達式必須有返回結果。例如 1 + 1,沒有結果的表達式不允許使用,如:var a = 1 + 1;
- 可以直接獲取Vue實例中定義的數據或函數
示例:
HTML:
<div id="app">{{name}}</div>
JS:
var app = new Vue({
el:"#app",
data:{
name:"Jack"
}
})
5.1.2.插值閃爍
使用{{}}方式在網速較慢時會出現問題。在數據未加載完成時,頁面會顯示出原始的{{}}
,加載完畢后才顯示正確數據,我們稱為插值閃爍。
我們將網速調慢一些,然后試試看剛才的案例:
刷新頁面:
5.1.3.v-text和v-html
使用v-text和v-html指令來替代{{}}
說明:
- v-text:將數據輸出到元素內部,如果輸出的數據有HTML代碼,會作為普通文本輸出
- v-html:將數據輸出到元素內部,如果輸出的數據有HTML代碼,會被渲染
示例:
HTML:
<div id="app">
v-text:<span v-text="hello"></span> <br/>
v-html:<span v-html="hello"></span>
</div>
JS:
var vm = new Vue({
el:"#app",
data:{
hello: "<h1>大家好,我是峰哥</h1>"
}
})
效果:
並且不會出現插值閃爍,當沒有數據時,會顯示空白。
5.2.v-model
剛才的v-text和v-html可以看做是單向綁定,數據影響了視圖渲染,但是反過來就不行。接下來學習的v-model是雙向綁定,視圖(View)和模型(Model)之間會互相影響。
既然是雙向綁定,一定是在視圖中可以修改數據,這樣就限定了視圖的元素類型。目前v-model的可使用元素有:
- input
- select
- textarea
- checkbox
- radio
- components(Vue中的自定義組件)
基本上除了最后一項,其它都是表單的輸入項。
舉例:
html:
<div id="app">
<input type="checkbox" v-model="language" value="Java" />Java<br/>
<input type="checkbox" v-model="language" value="PHP" />PHP<br/>
<input type="checkbox" v-model="language" value="Swift" />Swift<br/>
<h1>
你選擇了:{{language.join(',')}}
</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
language: []
}
})
</script>
- 多個
CheckBox
對應一個model時,model的類型是一個數組,單個checkbox值默認是boolean類型 - radio對應的值是input的value值
input
和textarea
默認對應的model是字符串select
單選對應字符串,多選對應也是數組
效果:
5.3.v-on
5.3.1.基本用法
v-on指令用於給頁面元素綁定事件。
語法:
v-on:事件名="js片段或函數名"
示例:
<div id="app">
<!--事件中直接寫js片段-->
<button v-on:click="num++">增加一個</button><br/>
<!--事件指定一個回調函數,必須是Vue實例中定義的函數-->
<button v-on:click="decrement">減少一個</button><br/>
<h1>有{{num}}個女神迷戀峰哥</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
num:100
},
methods:{
decrement(){
this.num--;
}
}
})
</script>
效果:
另外,事件綁定可以簡寫,例如v-on:click='add'
可以簡寫為@click='add'
5.3.2.事件修飾符
在事件處理程序中調用 event.preventDefault()
或 event.stopPropagation()
是非常常見的需求。盡管我們可以在方法中輕松實現這點,但更好的方式是:方法只有純粹的數據邏輯,而不是去處理 DOM 事件細節。
為了解決這個問題,Vue.js 為 v-on
提供了事件修飾符。修飾符是由點開頭的指令后綴來表示的。
.stop
:阻止事件冒泡到父元素.prevent
:阻止默認事件發生.capture
:使用事件捕獲模式.self
:只有元素自身觸發事件才執行。(冒泡或捕獲的都不執行).once
:只執行一次
阻止默認事件
<div id="app">
<!--右擊事件,並阻止默認事件發生-->
<button v-on:contextmenu.prevent="num++">增加一個</button>
<br/>
<!--右擊事件,不阻止默認事件發生-->
<button v-on:contextmenu="decrement($event)">減少一個</button>
<br/>
<h1>有{{num}}個女神迷戀峰哥</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
num: 100
},
methods: {
decrement(ev) {//此種定義方法的寫法需要idea中設置javascript的版本為ECMAScript6
// ev.preventDefault();
this.num--;
}
}
})
</script>
效果:(右鍵“增加一個”,不會觸發默認的瀏覽器右擊事件;右鍵“減少一個”,會觸發默認的瀏覽器右擊事件)
5.3.3.按鍵修飾符
在監聽鍵盤事件時,我們經常需要檢查常見的鍵值。Vue 允許為 v-on
在監聽鍵盤事件時添加按鍵修飾符:
<!-- 只有在 `keyCode` 是 13 時調用 `vm.submit()` -->
<input v-on:keyup.13="submit">
記住所有的 keyCode
比較困難,所以 Vue 為最常用的按鍵提供了別名:
<!-- 同上 -->
<input v-on:keyup.enter="submit">
<!-- 縮寫語法 -->
<input @keyup.enter="submit">
前提是:事件源對象要獲得焦點
全部的按鍵別名:
.enter
.tab
.delete
(捕獲“刪除”和“退格”鍵).esc
.space
.up
.down
.left
.right
5.3.4.組合按鈕
可以用如下修飾符來實現僅在按下相應按鍵時才觸發鼠標或鍵盤事件的監聽器。
.ctrl
.alt
.shift
例如:
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
5.4.v-for
遍歷數據渲染頁面是非常常用的需求,Vue中通過v-for指令來實現。
5.4.1.遍歷數組
語法:
v-for="item in items"
- items:要遍歷的數組,需要在vue的data中定義好。
- item:迭代得到的數組元素的別名
示例
<div id="app">
<ul>
<li v-for="user in users">
{{user.name}} - {{user.gender}} - {{user.age}}
</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
users:[
{name:'柳岩', gender:'女', age: 21},
{name:'峰哥', gender:'男', age: 18},
{name:'范冰冰', gender:'女', age: 24},
{name:'劉亦菲', gender:'女', age: 18},
{name:'古力娜扎', gender:'女', age: 25}
]
},
})
</script>
效果:
5.4.2.數組下標
在遍歷的過程中,如果我們需要知道數組下標,可以指定第二個參數:
語法
v-for="(item,index) in items"
- items:要迭代的數組
- item:迭代得到的數組元素別名
- index:迭代到的當前元素索引,從0開始。
示例
<ul>
<li v-for="(user, index) in users">
{{index + 1}}. {{user.name}} - {{user.gender}} - {{user.age}}
</li>
</ul>
效果:
5.4.3.遍歷對象
v-for除了可以迭代數組,也可以迭代對象。語法基本類似
語法:
v-for="value in object"
v-for="(value,key) in object"
v-for="(value,key,index) in object"
- 1個參數時,得到的是對象的屬性值
- 2個參數時,第一個是屬性值,第二個是鍵
- 3個參數時,第三個是索引,從0開始
示例:
<div id="app">
<ul>
<li v-for="(value, key, index) in user">
{{index + 1}}. {{key}} - {{value}}
</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
user:{name:'峰哥', gender:'男', age: 18}
}
})
</script>
效果:
5.4.4.key
當 Vue.js 用 v-for
正在更新已渲染過的元素列表時,它默認用“就地復用”策略。如果數據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數據項的順序, 而是簡單復用此處每個元素,並且確保它在特定索引下顯示已被渲染過的每個元素。
這個功能可以有效的提高渲染的效率。
但是需要DOM 元素來匹配數據項時,你需要給Vue一些提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一 key
屬性。理想的 key
值是每項都有的且唯一的 id。
示例:
<ul>
<li v-for="(item,index) in items" :key="item.id"></li>
</ul>
- 這里使用了一個特殊語法:
:key=""
我們后面會講到,它可以讓你讀取vue中的屬性,並賦值給key屬性 - 這里我們綁定的key是item.id,是唯一的
5.5.v-if和v-show
5.5.1.基本使用
v-if,顧名思義,條件判斷。當得到結果為true時,所在的元素才會被渲染。
語法:
v-if="布爾表達式"
示例:
<div id="app">
<button v-on:click="show = !show">點我呀</button>
<br>
<h1 v-if="show">
看到我啦?!
</h1>
<h1 v-show="show">
看到我啦?!show
</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
show: true
}
})
</script>
效果:
5.5.2.與v-for結合
當v-if和v-for出現在一起時,v-for優先級更高。也就是說,會先遍歷,再判斷條件。
修改v-for中的案例,添加v-if:
<ul>
<li v-for="(user, index) in users" v-if="user.gender == '女'">
{{index + 1}}. {{user.name}} - {{user.gender}} - {{user.age}}
</li>
</ul>
效果:
只顯示女性用戶信息
5.5.3.v-else
你可以使用 v-else
指令來表示 v-if
的“else 塊”:
<div id="app">
<h1 v-if="Math.random() > 0.5">
看到我啦?!if
</h1>
<h1 v-else>
看到我啦?!else
</h1>
</div>
v-else
元素必須緊跟在帶 v-if
或者 v-else-if
的元素的后面,否則它將不會被識別。
v-else-if
,顧名思義,充當 v-if
的“else-if 塊”,可以連續使用:
<div id="app">
<button v-on:click="random=Math.random()">點我呀</button><span>{{random}}</span>
<h1 v-if="random >= 0.75">
看到我啦?!if
</h1>
<h1 v-else-if="random > 0.5">
看到我啦?!if 0.5
</h1>
<h1 v-else-if="random > 0.25">
看到我啦?!if 0.25
</h1>
<h1 v-else>
看到我啦?!else
</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
random: 1
}
})
</script>
類似於 v-else
,v-else-if
也必須緊跟在帶 v-if
或者 v-else-if
的元素之后。
演示:
5.5.4.v-show
另一個用於根據條件展示元素的選項是 v-show
指令。用法大致一樣:
<h1 v-show="ok">Hello!</h1>
不同的是帶有 v-show
的元素始終會被渲染並保留在 DOM 中。v-show
只是簡單地切換元素的 CSS 屬性 display
。
示例:
<div id="app">
<!--事件中直接寫js片段-->
<button v-on:click="show = !show">點擊切換</button><br/>
<h1 v-if="show">
你好
</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
show:true
}
})
</script>
代碼:
5.6.v-bind
html屬性不能使用雙大括號形式綁定,只能使用v-bind指令。
<div id="app">
<!--可以是數據模型,可以是具有返回值的js代碼塊或者函數-->
<div v-bind:title="title" style="border: 1px solid red; width: 50px; height: 50px;"></div>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
title: "title",
}
})
</script>
效果:
在將 v-bind
用於 class
和 style
時,Vue.js 做了專門的增強。表達式結果的類型除了字符串之外,還可以是對象或數組。
5.6.1.綁定class樣式
數組語法
我們可以借助於v-bind
指令來實現:
HTML:
<div id="app">
<div v-bind:class="activeClass"></div>
<div v-bind:class="errorClass"></div>
<div v-bind:class="[activeClass, errorClass]"></div>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
activeClass: 'active',
errorClass: ['text-danger', 'text-error']
}
})
</script>
渲染后的效果:(具有active和errorClass的樣式)
對象語法
我們可以傳給 v-bind:class
一個對象,以動態地切換 class:
<div v-bind:class="{ active: isActive }"></div>
上面的語法表示 active
這個 class 存在與否將取決於數據屬性 isActive
的 truthiness(所有的值都是真實的,除了false,0,“”,null,undefined和NaN)。
你可以在對象中傳入更多屬性來動態切換多個 class。此外,v-bind:class
指令也可以與普通的 class 屬性共存。如下模板:
<div class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>
和如下 data:
data: {
isActive: true,
hasError: false
}
結果渲染為:
<div class="static active"></div>
active樣式和text-danger樣式的存在與否,取決於isActive和hasError的值。本例中isActive為true,hasError為false,所以active樣式存在,text-danger不存在。
通常情況下,綁定的數據對象不必內聯定義在模板里:
<div class="static" v-bind:class="classObject"></div>
數據:
data: {
classObject: {
active: true,
'text-danger': false
}
}
效果和之前一樣:
<div class="static active"></div>
5.6.2.綁定style樣式
數組語法
數組語法可以將多個樣式對象應用到同一個元素上:
<div v-bind:style="[baseStyles, overridingStyles]"></div>
數據:
data: {
baseStyles: {'background-color': 'red'},
overridingStyles: {border: '1px solid black'}
}
渲染后的結果:
<div style="background-color: red; border: 1px solid black;"></div>
對象語法
v-bind:style
的對象語法十分直觀——看着非常像 CSS,但其實是一個 JavaScript 對象。CSS 屬性名可以用駝峰式 (camelCase) 或短橫線分隔 (kebab-case,記得用單引號括起來) 來命名:
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
數據:
data: {
activeColor: 'red',
fontSize: 30
}
效果:
<div style="color: red; font-size: 30px;"></div>
直接綁定到一個樣式對象通常更好,這會讓模板更清晰:
<div v-bind:style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
效果同上。
5.6.3.簡寫
v-bind:class
可以簡寫為:class
5.7.計算屬性
在插值表達式中使用js表達式是非常方便的,而且也經常被用到。
但是如果表達式的內容很長,就會顯得不夠優雅,而且后期維護起來也不方便,例如下面的場景,我們有一個日期的數據,但是是毫秒值:
data:{
birthday:1529032123201 // 毫秒值
}
我們在頁面渲染,希望得到yyyy-MM-dd的樣式:
<h1>您的生日是:{{
new Date(birthday).getFullYear() + '-'+ new Date(birthday).getMonth()+ '-' + new Date(birthday).getDay()
}}
</h1>
雖然能得到結果,但是非常麻煩。
Vue中提供了計算屬性,來替代復雜的表達式:
var vm = new Vue({
el:"#app",
data:{
birthday:1429032123201 // 毫秒值
},
computed:{
birth(){// 計算屬性本質是一個方法,但是必須返回結果
const d = new Date(this.birthday);
return d.getFullYear() + "-" + d.getMonth() + "-" + d.getDay();
}
}
})
- 計算屬性本質就是方法,但是一定要返回數據。然后頁面渲染時,可以把這個方法當成一個變量來使用。
頁面使用:
<div id="app">
<h1>您的生日是:{{birth}} </h1>
</div>
效果:
我們可以將同一操作定義為一個方法而不是一個計算屬性。兩種方式的最終結果確實是完全相同的。然而,不同的是計算屬性是基於它們的依賴進行緩存的。計算屬性只有在它的相關依賴發生改變時才會重新求值。這就意味着只要birthday
還沒有發生改變,多次訪問 birthday
計算屬性會立即返回之前的計算結果,而不必再次執行函數。
5.8.watch
watch可以讓我們監控一個值的變化。從而做出相應的反應。
示例:
<div id="app">
<input type="text" v-model="message">
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
message:""
},
watch:{
message(newVal, oldVal){
console.log(newVal, oldVal);
}
}
})
</script>
效果: