Reactive Bootstrap 从 0 到 1
Talk is Cheap, Show Me the Code.
index.hml
<div id="app"></div>
<script src="app.js"><script>
reactive.js
/* reactive module */
let watchingFn = null;
function observe(data) {
// 收集 data 各个字段的监听函数
const depends = {};
return new Proxy(data, {
get(obj, key) {
if (watchingFn) {
if (!depends[key]) {
depends[key] = [];
}
depends[key].push(watchingFn); // 注册
}
return obj[key];
},
set(obj, key, value) {
obj[key] = value;
if (depends[key]) {
depends[key].forEach(fn => fn()); // 执行
}
}
});
}
// 注册函数 fn 到 depends[key] 中,并执行函数
function watcher(fn) {
watchingFn = fn;
fn();
watchingFn = null;
}
App.js
// --- App ---
// 1. 拦截 data, 并返回 Proxy
const data = observe({
count: 10,
doubleCount: 10 * 2
});
// 2. 注册依赖
// 调用 count 属性的 getter 方法,
// 将匿名函数注册到 depends[key] 中
watcher(() => {
data.doubleCount = data.count * 2;
});
// 3. 声明 render,并注册 render 到所引用的字段的 depends 中
function render() {
document.getElementById('app').innerHTML = `
<div>Count: ${data.count}</div>
<div>DoubleCount: ${data.doubleCount}</div>
<div>
<button @click="increment">+ increment</button>
<button @click="decrement">- decrement</button>
</div>
`;
}
// 调用 count 和 doubleCount 属性的 getter 方法,
// 将 render 函数分别注册到 对应depends[key] 中
watcher(render);
// 4. 测试一下
data.count = 100;
// 5. 实现事件监听
const methods = {
increment() {
data.count++
},
decrement() {
data.count--
}
};
document.getElementById('app')
.addEventListener('click', ev => {
const clickAttr = ev.target.attributes['@click'];
const methodName = clickAttr && clickAttr.value;
if (methodName) {
methods[methodName]();
}
});