1. 程式人生 > >Vuejs - 強大的指令系統

Vuejs - 強大的指令系統

ont select dex prev BE 源碼 filter -h 書寫

Vuejs 中,指令(Directives)是帶有 v- 前綴的特殊屬性。指令屬性的預期值是 單個 Javascript 表達式(v-for 是個例外)。指令的職責是,當表達式改變時,將其產生的連帶影響,響應式的作用於 DOM。

當然,Vue 除了核心功能默認內置的指令外,更強大的是它允許註冊自定義指令,這是個讓我非常驚喜功能。因為當初在使用 Angular1.x 時就特別喜好自定義指令這個功能,沒想到 Vue 也借鑒了進來,讓我能夠靈活對 DOM 進行底層操作,而且它具有非常高的復用性,書寫起來也非常簡潔。

當然在 Vue 中,代碼的復用和抽象的主要形式還是 組件,這將在下一節中講到。

內置指令

Vue 提供供了大概 13 種內置指令,基本上能夠滿足我們的日常開發需求,不得不說作者考慮的已經非常全面,給尤大大點贊。這裏只介紹 v-for、v-on 兩種內置指令,感興趣的可以到 官方API 了解。

1.v-for

上一節我們已經使用過了,它是基於源數據多次渲染元素或莫板塊的。此指令的值,必須使用特定語法 alias in expression 來進行輸出。 expression 為需要遍歷的對象,它可以是 Array | Object | number | string 四種類型,alias 為遍歷的元素別名。這個跟 js 的遍歷函數 map 很相似,先來看個例子:

1
2
3
4
5
6
7
<div id="app1">
<ul>
<li v-for="item in 5">
{{ item }}
</li>
</ul>
</div>
1
2
3
var app1 = new Vue({
el: "#app1",
})

這裏是在頁面上依次輸出 1~5 的數字,此時 expression5number(number 必須為正整數) 類型。 Vue 在渲染時,會先創建一個長度為 5 的數組,然後遍歷輸出 item + 1 的值。如果為 string 類型,就會創建一個該字符串長度的數組,再遍歷輸出字符串的每個字符。單純講肯定不太好理解,其實這部分源碼很簡單,大家可以直接通過閱讀來理解:官方源碼。

大多數時候,expression 都只是個數組,其實知道它還可以為 string 或者 number 是很有用的,比如我們需要快速重復輸出一個DOM,使用 number 能很快實現,節約了我們復制粘貼或者書寫數組列表的時間。當為 string 時,我們可以根據需求依次輸出每個字符,以此可以做出很炫酷的打字效果,如下:

1
2
3
<div id="app2">
<span v-for="(item, index) in name" v-bind:style="{animationDelay: `${0.5 + index * 0.3}s`}">{{ item }}</span>
</div>
1
2
3
4
5
6
7
8
9
10
11
#app2 span {
animation: flip-in 1s 0s ease-in-out both;
}
@keyframes flip-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
1
2
3
4
5
6
7
8
9
// demo 2
var app2 = new Vue({
el: "#app2",
data () {
return {
name: ‘yugasun‘
}
}
})

怎麽樣?曾今看到別人做出炫酷的打字效果簡歷是不是很羨慕,這裏只需要20行代碼就可以實現打字效果,趕緊動手試試吧~

註意: 這裏在設置每個字符的 animation-delay 屬性時,用到了 v-bind 指令,這個很簡單,這裏不做贅述。同時使用了 ES6 的模板字符語法來計算時延的值,如果瀏覽器不支持,建議更換為新版 Chrome 瀏覽器。模板字符串 教程在這裏。

2.v-on

v-on 指令是用來綁定事件監聽器的,事件類型可以是DOM原生事件,也可以是通過 $emit 觸發的自定義事件。但是只有用在自定義元素組件上時,才可以監聽組件觸發的自定義事件。

在監聽原生 DOM 事件時,方法以事件為唯一的參數。如果使用內聯語句,語句可以訪問一個 $event 屬性:v-on:click="handle(‘ok‘, $event)"

看代碼更好理解:

1
2
3
4
5
<div id="app3">
<button v-on:click="handleClick(‘確定‘, $event)">確定</button>
<button v-on:click="handleClick(‘取消‘, $event)">取消</button><br>
{{ msg }}
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var app3 = new Vue({
el: "#app3",
data () {
return {
btnText: ‘‘
}
},
computed: {
msg () {
return this.btnText ? `點擊了 ${this.btnText} 按鈕` : ‘您還沒點擊任何按鈕‘
}
},
methods: {
handleClick (text, e) {
console.log(e)
this.btnText = text
}
}
})

這裏通過 v-on 監聽了兩個按鈕的點擊事件,並分別傳遞了各自的文字到監聽函數進行輸出,輸出的 msg 是計算屬性(如果不懂什麽是計算屬性,教程在這裏 深入淺出響應式系統),依賴 btnText 動態計算的。可以通過控制臺查看打印出的參數 e 對象就是一個原生 MouseEvent 對象。

除了基本的用法, v-on 指令還提供了豐富的 修飾符 來配合使用,這樣可以寫出非常靈活的監聽事件,比如我們經常使用的 e.preventDefault(),在 Vue 中我們只需要通過 v-on:click.prevent 就可以實現了,是不是很炫酷,所有的修飾符列表在 這裏。這裏我們來演示下,點擊鼠標左鍵和右鍵的事件監聽,將上面的 html 代碼修改如下:

1
2
3
4
5
6
<div id="app3">
<!-- 相對於上面只添加了 `.left` 和 `.right` 修飾符 -->
<button v-on:click.left="handleClick(‘確定‘, $event)">確定</button>
<button v-on:click.right="handleClick(‘取消‘, $event)">取消</button><br>
{{ msg }}
</div>

自定義指令

最讓我激動人心的就是自定義指令了,它即可以通過 Vue.directive 註冊全局指令,也可以給 Vue 實例添加 directives 屬性來註冊局部指令。這兩種指令都是通過指令定義時的鉤子函數實現的。

關於鉤子函數和鉤子函數參數介紹請直接閱讀官方文檔,官方文檔已經講述的非常詳細了,這裏不再贅述,直通車:鉤子函數、鉤子函數參數

相信你們已經很快看完了官方文檔介紹了,好了現在我將帶你來領略自定義指令的強大,實現一個倒計時指令。

鉤子函數 bind 是在元素第一次綁定到元素時調用的,所以我們可以在這裏初始化綁定的元素 el,而且綁定元素已經作為所有鉤子函數的第一個參數被傳入,這裏可以通過 el.innerHTML 就很容易修改綁定元素的內容了,代碼如下:

1
2
3
4
<div id="app4">
<button v-on:click="startCount">開始倒計時</button>
<span data-count="60" v-count-down="count" v-if="show" style="font-size:16px;"></span>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var app4 = new Vue({
el: ‘#app4‘,
data () {
return {
show: false, // 是否顯示倒計時
timer: null // 定時器
}
},
methods: {
startCount: function () {
this.show = true
}
},
directives: {
‘count-down‘: {
bind: function (el, binding, vnode) {
el.innerHTML = ‘60‘
}
}
}
})

當我們點擊按鈕是,將 show 置為 true,此時 v-if 指令就判斷顯示使用 v-count-down 指令的元素,然後執行 bind 初始化函數,將元素內容修改為 60。這裏很好理解。但是我們要實現倒計時,就需要創建一個定時器,並需要維護一個數實現遞減,這裏通過動態修改 data-count 的值來實現。

實現思路:當初始化時,創建一個定時器,每隔1s將獲取 data-count 的值減一,然後賦給 el.innerHTML,同時修改 data-count 屬性為新的值,當然還需要添加判斷,就是當然 data-count 為0時,清除計時器。

有了思路,實現代碼就非常簡單了:

1
2
3
4
5
6
<div id="app4">
<button v-on:click="startCount">開始倒計時</button>
<span v-count-down data-count="60" v-if="show" style="font-size:16px;">
60
</span>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var app4 = new Vue({
el: ‘#app4‘,
data () {
return {
show: false, // 是否顯示倒計時
}
},
methods: {
startCount: function () {
this.show = true
}
},
directives: {
‘count-down‘: {
bind: function (el, binding, vnode) {
let count = parseInt(el.getAttribute(‘data-count‘))
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
// 大家可以推測下這裏的 this 指什麽?
this.timer = setInterval(function () {
if (count <= 0) {
clearInterval(this.timer)
this.timer = null
} else {
count--
el.innerHTML = count
el.setAttribute(‘data-count‘, count)
}
}, 1000)
}
}
}
})

Vuejs - 強大的指令系統