經過上一篇文章的學習,實現了介面驅動資料更新,接下來實現一下其它相關的指令,比如事件相關的指令,v-on 這個指令的使用頻率還是很高的,所以我們先來實現這個指令。
v-on 的作用是什麼,是不是可以給某一個元素繫結一個事件。
緊接著瞭解了 v-on 的作用之後,我在 example.html 的結構程式碼當中新增了一個 div 用 v-on 繫結了一個點選事件,然後在 methods 當中新增了一個 myFn 的方法,然後在點選事件觸發的時候呼叫了 myFn 方法。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue基本模板</title>
<script src="js/nue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="name"/>
<div v-on:click="myFn">我是div</div>
</div>
<script>
let vue = new Nue({
el: document.querySelector('#app'),
data: {
name: "BNTang"
},
methods: {
myFn() {
alert('myFn被執行了');
},
}
});
</script>
</body>
</html>
如上已經將基本的結構搭建完畢了,現在需要做的事情就是需要處理一下 v-on 這個指令。
首先來看我們自己編寫的 Nue 原始碼,在建立 Nue 範例的時候, 呼叫了 new Compiler(this);,進入 Compiler,constructor 方法繼續往下看, 在進入 this.buildTemplate(fragment);,遍歷所有的節點,判斷是否是一個元素時,呼叫了 this.buildElement(node);, 進入 buildElement 方法,可以看到之前就是在這裡處理了 v-model 這個指令,現在我們需要在這裡處理 v-on 這個指令。
我先將 name, value 列印到控制檯,輸出結果如下:
type text
v-model name
v-on:click myFn
可以得出如果我們編寫的是 v-model,那麼 name 就是 v-model,value 就是 name,如果編寫的是 v-on:click,那麼 name 就是 v-on:click,value 就是 myFn。
知道了這些資訊之後就可以開展下一步了,我在將 name 按照 :
進行分割一次就會拿到的是 v-on 與 click,click 就是待會我們要註冊的事件型別,在用解構的方式將 name, value 取出來,程式碼如下:
let [directiveName, directiveType] = name.split(':');
directiveName 就是 v-on,directiveType 就是 click。
然後再將之前的程式碼 name.split('-'); 改寫為 directiveName.split('-');, 這個時候我們將解構出來的結果如下:
model
on
這個時候就可以在之前的工具類當中新增一個 on 方法, 來用處理 v-on,在新增 on 方法之前,改造一下根據指令名稱, 呼叫不同的處理常式的程式碼,將之前的程式碼改寫為如下:
CompilerUtil[directive](node, value, this.vm, directiveType);
多了一個 directiveType 引數,這個引數就是指令的型別,比如 v-on:click,那麼 directiveType 就是 click,這個時候就可以在工具類當中新增一個 on 方法了,程式碼如下:
on: function (node, value, vm, type) {
node.addEventListener(type, (e) => {
alert('事件註冊成功了');
});
}
這個時候我們在頁面上點選 div 的時候,就會彈出一個提示框,說明事件註冊成功了。
事件註冊成功了是沒問題,但是這個事件執行的內容,是自己的,並不是通過 v-on 繫結的,所以我們需要將這個事件執行的內容改為通過 v-on 繫結的,這個時候就需要用到之前的 methods 物件了,我們需要通過 methods 物件來獲取到對應的方法,然後將這個方法執行。
接下來要改造一下建立 Nue 範例的時候,將 methods 儲存起來,改造一下 Nue 的建構函式,以後在根據對應的方法名稱,獲取到對應的方法, 再執行即可,程式碼如下:
this.$methods = options.methods;
改造完畢之後,我們就可以在工具類當中的 on 方法當中,通過 methods 物件獲取到對應的方法,然後執行即可,程式碼如下:
on: function (node, value, vm, type) {
node.addEventListener(type, (e) => {
vm.$methods[value](e);
});
}
這個時候我們在頁面上點選 div 的時候,就會彈出一個提示框,說明事件註冊成功了,並且事件執行的內容也是通過 v-on 繫結的。
在 myFn 方法中列印一下 this,發現並不是 Nue 的範例,而是 myFn 本身:
這個時候就需要將 myFn 的 this 改為 Nue 的範例,這個時候就需要用到 call 方法了,程式碼如下:
node.addEventListener(type, (e) => {
vm.$methods[value].call(vm, e);
});
call 方法的第一個引數是改變 this 的指向,第二個引數是傳遞的引數,這個時候我們在 myFn 方法中列印一下 this,發現已經是 Nue 的範例了。
到此為止,v-on 指令的實現已經完成了。