通过Object.defineProperty模拟实现Vue中,数据变化,视图跟着变化的效果。
html代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
font-size: 20px;
}
.box {
box-sizing: border-box;
width: 300px;
border: 2px solid #aaa;
padding: 10px;
margin: 0 auto;
}
.box div {
padding: 10px 0;
}
</style>
</head>
<body>
<div class="box">
<div class="name-line">
姓名:<span></span>
</div>
<div class="age-line">
年龄:<span></span>
</div>
<div class="bankMoney-line">
银行中的钱:<span></span>
</div>
<div class="wechatMoney-line">
微信中的钱:<span></span>
</div>
<div class="totalMoney-line">
总的钱:<span></span>
</div>
</div>
<script src="./index.js"></script>
</body>
</html>
js代码:
const user = {
name: '张三',
age: 18,
bankMoney: 2000,
wechatMoney: 200
}
for (let key in user) {
// 内部的临时变量
let interVal = user[key]
// 函数数组,保存着读取了当前属性的函数
const funcs = []
Object.defineProperty(user, key, {
get: () => {
// 将读取了当前属性的函数存入数组中
if (!funcs.includes(window.__func) && window.__func) {
funcs.push(window.__func)
}
return interVal
},
set: (val) => {
interVal = val
// 重新执行与当前属性相关的函数
for (let i = 0; i < funcs.length; i++) {
funcs[i]()
}
}
})
}
function renderName () {
document.querySelector('.name-line span').textContent = user.name
}
function renderAge () {
document.querySelector('.age-line span').textContent = user.age
}
function renderBankMoney () {
document.querySelector('.bankMoney-line span').textContent = user.bankMoney
}
function renderWechatMoney () {
document.querySelector('.wechatMoney-line span').textContent = user.wechatMoney
}
function renderTotalMoney () {
document.querySelector('.totalMoney-line span').textContent = user.bankMoney + user.wechatMoney
}
function execFunc (fn) {
window.__func = fn
fn()
window.__func = null
}
execFunc(renderName)
execFunc(renderAge)
execFunc(renderBankMoney)
execFunc(renderWechatMoney)
execFunc(renderTotalMoney)
数据不做修改:
当数据修改后,视图自动更新:
// 随意改变数据,能够让视图变化
user.age = 22
user.bankMoney = 3000
user.wechatMoney = 100
原理简要说明:
利用Object.defineProperty()对user对象中的每个属性进行属性描述符的重写,当运行了需要调用该属性的函数时,将函数存入数组。之后,将数据修改时,重新执行一遍数组中的所有函数,因此,视图中的数据得以更新。