从头开始实现反应性
响应式是许多 Web 界面的核心。它使编写健壮且交互性强的 Web 应用变得非常容易。虽然大多数框架都内置了响应式功能,但在纯 JavaScript 中,你总会有需要响应式的时候。所以,我将在这里向你展示如何在 JavaScript 中实现响应式。
等一下...反应性是什么?
有很多解释,目前为止最好的解释是这个。但在这里,我将向您展示一个更容易理解的代码示例。
假设你有这个:
let who = 'Siddharth';
document.querySelector('h1').innerText = who;
稍后,您更改who
:
who = 'Somebody';
但是 H1 中的内容直到我们document.querySelector('h1').innerText = who;
再次调用才会改变。这就是响应式的作用所在。document.querySelector('h1').innerText = who;
当引用的变量发生变化时,它会自动重新运行代码(在我们的例子中是)。因此,当我们更改变量时,更改会自动反映在代码中。
引擎
注意:为了让本教程简洁(且有趣!),我不会实现错误处理、对象以及所有那些枯燥的检查。本教程的下一部分(如果我写的话!)会详细介绍其中的一些内容。
首先,让我们构建一个我们需要做出反应的对象:
let data = {
name: 'John Doe',
age: 25
};
使其具有反应性的一种方法是让 setter/getter 监听事件并对其做出反应。
const obj = {
data: [],
get foo() {
return this.data.join(', ');
},
set foo(val) {
this.data.push(val);
}
}
obj.foo = 1;
obj.foo = 2;
obj.foo = 3;
obj.foo; //=> 1, 2, 3
在构建反应性时,Setter 和 Getter 非常有用 |
---|
因此,我们需要将对象更改为如下形式:
let data = {
name: 'John Doe',
get name () {
return this.name;
},
set name (val) {
this.name = name;
// TODO notify
}
};
使用它的代码如下所示:
const data = new Reactive({
name: 'John Doe',
age: 25
});
data.listen('name', val => console.log('name was changed to ' + val));
data.contents.name = 'Siddharth';
//=> name was changed to Siddharth
那么,让我们首先构建这个Reactive
类:
class Reactive {
constructor(obj) {/* TODO */}
listen(prop) {/* TODO */}
}
构造函数非常简单,只需设置数据并开始观察:
constructor (obj) {
this.contents = obj;
this.listeners = {}; // Will be explained later
this.makeReactive(obj);
}
现在,我们将实现makeReactive
:
makeReactive(obj) {
Object.keys(obj).forEach(prop => this.makePropReactive(obj, prop));
}
现在,我们将实现makePropReactive
:
makePropReactive(obj, key) {
let value = obj[key]; // Cache
Object.defineProperty(obj, key, {
get () {
return value;
},
set (newValue) {
value = newValue;
this.notify(key);
}
});
}
在这里,我们使用Object.defineProperty
在对象上设置 getter。
接下来要做的是设置一个通知器和一个监听器。监听器非常简单:
listen(prop, handler) {
if (!this.listeners[prop]) this.listeners[prop] = [];
this.listeners[prop].push(handler);
}
在这里,我们将对象上的监听器设置为数组中的值。
接下来通知:
notify(prop) {
this.listeners[prop].forEach(listener => listener(this.contents[prop]));
}
好了,就到这里!以下是完整代码:
class Reactive {
constructor (obj) {
this.contents = obj;
this.listeners = {};
this.makeReactive(obj);
}
makeReactive(obj) {
Object.keys(obj).forEach(prop => this.makePropReactive(obj, prop));
}
makePropReactive(obj, key) {
let value = obj[key];
// Gotta be careful with this here
const that = this;
Object.defineProperty(obj, key, {
get () {
return value;
},
set (newValue) {
value = newValue;
that.notify(key)
}
});
}
listen(prop, handler) {
if (!this.listeners[prop]) this.listeners[prop] = [];
this.listeners[prop].push(handler);
}
notify(prop) {
this.listeners[prop].forEach(listener => listener(this.contents[prop]));
}
}
很简单,不是吗?下面是回复:
感谢阅读!在接下来的部分中,我们将进一步探讨如何改进此功能。
文章来源:https://dev.to/siddharthshyniben/implementing-reactivity-from-scratch-51op