JavaScript 之實現一個簡單的 Vue
vue的使用相信大家都很熟練了,使用起來簡單。但是大部分人不知道其內部的原理是怎麼樣的,今天我們就來一起實現一個簡單的vue
Object.defineProperty()
實現之前我們得先看一下Object.defineProperty的實現,因為vue主要是通過資料劫持來實現的,通過 get
、 set
來完成資料的讀取和更新。
-
var obj = {name:'wclimb'}
-
var age = 24
-
Object.defineProperty(obj,'age',{
-
enumerable: true, // 可列舉
-
configurable: false, // 不能再define
-
get () {
-
return age
-
},
-
set (newVal) {
-
console.log('我改變了',age +' -> '+newVal);
-
age = newVal
-
}
-
})
-
> obj.age
-
> 24
-
> obj.age = 25;
-
> 我改變了 24 -> 25
-
> 25
從上面可以看到通過 get
獲取資料,通過 set
監聽到資料變化執行相應操作,還是不明白的話可以去看看Object.defineProperty文件。
流程圖
html程式碼結構
-
<div id="wrap">
-
<p v-html="test"></p>
-
<input type="text" v-model="form">
-
<input type="text" v-model="form">
-
<button @click="changeValue">改變值</button>
-
{{form}}
-
</div>
js呼叫
-
new Vue({
-
el: '#wrap',
-
data:{
-
form: '這是form的值',
-
test: '<strong>我是粗體</strong>',
-
},
-
methods:{
-
changeValue(){
-
console.log(this.form)
-
this.form = '值被我改變了,氣不氣?'
-
}
-
}
-
})
Vue結構
-
class Vue{
-
constructor(){}
-
proxyData(){}
-
observer(){}
-
compile(){}
-
compileText(){}
-
}
-
class Watcher{
-
constructor(){}
-
update(){}
-
}
-
Vue constructor
建構函式主要是資料的初始化 -
proxyData
資料代理 -
observer
劫持監聽所有資料 -
compile
解析dom -
compileText
解析dom
裡處理純雙花括號的操作 -
Watcher
更新檢視操作
Vue constructor 初始化
-
class Vue{
-
constructor(options = {}){
-
this.$el = document.querySelector(options.el);
-
let data = this.data = options.data;
-
// 代理data,使其能直接this.xxx的方式訪問data,正常的話需要this.data.xxx
-
Object.keys(data).forEach((key)=> {
-
this.proxyData(key);
-
});
-
this.methods = obj.methods // 事件方法
-
this.watcherTask = {}; // 需要監聽的任務列表
-
this.observer(data); // 初始化劫持監聽所有資料
-
this.compile(this.$el); // 解析dom
-
}
-
}
上面主要是初始化操作,針對傳過來的資料進行處理
proxyData 代理data
-
class Vue{
-
constructor(options = {}){
-
......
-
}
-
proxyData(key){
-
let that = this;
-
Object.defineProperty(that, key, {
-
configurable: false,
-
enumerable: true,
-
get () {
-
return that.data[key];
-
},
-
set (newVal) {
-
that.data[key] = newVal;
-
}
-
});
-
}
-
}
上面主要是代理 data
到最上層, this.xxx
的方式直接訪問 data
observer 劫持監聽
-
class Vue{
-
constructor(options = {}){
-
......
-
}
-
proxyData(key){
-
......
-
}
-
observer(data){
-
let that = this
-
Object.keys(data).forEach(key=>{
-
let value = data[key]
-
this.watcherTask[key] = []
-
Object.defineProperty(data,key,{
-
configurable: false,
-
enumerable: true,
-
get(){
-
return value
-
},
-
set(newValue){
-
if(newValue !== value){
-
value = newValue
-
that.watcherTask[key].forEach(task => {
-
task.update()
-
})
-
}
-
}
-
})
-
})
-
}
-
}
同樣是使用 Object.defineProperty
來監聽資料,初始化需要訂閱的資料。
把需要訂閱的資料到 push
到 watcherTask
裡,等到時候需要更新的時候就可以批量更新資料了。