下面咱們將經過這三點來實現一個簡易的mvvm, 從而加深對Vue響應式的理解bash
Vue2實現數據劫持是利用ES5的 Object.defineProperty , 利用它會爲對象添加get/set方法,從而監聽屬性的讀取與修改。app
// html代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<h1>{{name}}</h1>
<p>身份:{{about.title}}</p>
<p>夢想:找到{{about.dream}},併成爲海賊王。</p>
<p>惡魔果實:{{about.fruit}}。</p>
他的標誌性特徵是一頂草帽,所以常被直接稱呼爲「{{about.alias}}」
</div>
<!--實現的mvvm-->
<script src="./mvvm.js"></script>
<script>
let mvvm = new Mvvm({
el: '#app',
data: {
name: '蒙奇·D·路飛',
about: {
title: '草帽海賊團船長',
dream: 'ONE PIECE',
fruit: '超人系橡膠果實',
alias: '草帽'
}
}
});
</script>
</body>
</html>
複製代碼
// 建立一個Mvvm構造函數,參數是一個選項對象
class Mvvm {
constructor(options = {}) {
this.$options = options;
this._data = this.$options.data;
// 經過 observe 劫持data對象,從而監聽其內部屬性
observe(this._data)
}
}
複製代碼
function Observe(data) {
for (let key in data) {
let val = data[key]
// 開頭調用 observe 判斷當前屬性是否爲一個對象,
// 若是是一個對象, 則遞歸調用Observe 確保監聽到深層屬性
observe(val)
// 經過 Object.defineProperty 爲每個屬性添加get/set方法
// 當屬性被讀取時會觸發get ,屬性被修改時觸發set
Object.defineProperty(data, key, {
configurable: true,
get() {
return val;
},
set(newVal) {
if (val === newVal) return;
val = newVal;
// 這裏咱們打一個log 測試時使用
console.log('數據被修改')
// 確保新屬性的值是一個對象時也能監聽到其內部屬性
observe(newVal);
}
})
}
}
function observe(data) {
if(!data || typeof data !== 'object') return;
return new Observe(data)
}
複製代碼
數據劫持基本已經完成,下面咱們來看一看observe是否有效mvvm
打開控制檯,輸入mvvm, 能夠看到_data中的屬性都被添加上了get/set方法函數
咱們測試一下修改屬性是否能觸發set, 能夠看到數據修改並打印了logpost
當咱們將一個屬性值修改成一個對象,這個新對象中的屬性是沒有被observe監聽到的,因此咱們須要再set時調用一下observe來確能監聽到新對象的屬性測試
例如: 當咱們將name屬性值修改成一個對象,當沒有在set中調用observe時是這樣的ui
調用了observe(newVal)時