Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目描述
目前国内90%的前端开发者都会使用vue,那你用了这么长时间的vue,是如何看待vue响应式的?能简单说说它是如何实现的吗?
考察点
- vue响应式的理解
- 劫持对象属性的实现
- 发布订阅模式的使用
解题思路
- 流程:
- 实例化Vue对象
- 解析el模板Compile -> 初始化View视图
- Observer劫持所有data属性-> 每个属性各生成一个发布者 -> 添加订阅 -> 监听变化通知订阅者 -> 更新View视图
- 修改数据如何监听发生改变?
- Object.defineProperty -> 劫持对象属性
- 当数据改变如何通知界面刷新?
- 发布订阅模式
实现
class Vue {
constructor(options) {
// 保存数据
this.$options = options;
this.$el = options.el;
this.$data = options.data;
// 将数据添加到响应式系统中
new Observer(this.$data);
// 代理数据
Object.keys(this.$data).map(key => {
this._proxy(key)
})
// 处理DOM
new Compiler(this.$el, this);
}
_proxy(key) {
Object.defineProperty(this, key, {
enumerable: true,
configurable: true,
get() {
return this.$data[key]
},
set(newValue) {
this.$data[key] = newValue;
}
})
}
}
class Observer {
constructor(data) {
this.data = data;
Object.keys(this.data).map(key => {
this.defineReactive(this.data, key, this.data[key])
})
}
defineReactive(data, key, val) {
const dep = new Dep();
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get() {
if (Dep.traget) {
dep.addSub(Dep.traget);
Dep.traget = null;
}
return val;
},
set(newValue) {
if (newValue === val) return;
val = newValue;
dep.notify();
}
})
}
}
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.map(sub => {
sub.updated();
})
}
}
class Watcher {
constructor(node, name, vm) {
this.node = node;
this.name = name;
this.vm = vm;
Dep.traget = this;
this.updated();
}
updated() {
this.node.nodeValue = this.vm[this.name];
this.node.value = this.vm[this.name];
this.node.innerHTML = this.vm[this.name];
}
}
const reg = /\{\{(.*)\}\}/;
class Compiler {
constructor(el, vm) {
this.el = document.querySelector(el)
this.vm = vm;
this.flag = this._createFragment();
this.el.appendChild(this.flag);
}
_createFragment() {
const flag = document.createDocumentFragment();
let child;
while (child = this.el.firstChild) {
this._compile(child);
flag.appendChild(child);
}
return flag;
}
_compile(node) {
if (node.nodeType == 3) {
if (reg.test(node.nodeValue)) {
const name = RegExp.$1.trim();
new Watcher(node, name, this.vm);
}
}
if (node.nodeType == 1) {
const attrs = node.attributes;
let name;
if (attrs.hasOwnProperty("v-model")) {
name = attrs["v-model"].nodeValue;
node.addEventListener("input", e => {
this.vm[name] = e.target.value;
});
} else {
if (reg.test(node.outerHTML)) {
name = RegExp.$1.trim();
}
}
new Watcher(node, name, this.vm);
}
}
}
以上,是我早期进行vue2学习,简单实现了vue2机制的一套代码,其中,涉及到vue响应式的主要做的任务是在Observer将数据添加到响应式系统中,其中用将数据遍历用Object.defineProperty做代理处理,通过Dep做发布订阅,每当数据改变都要通知当前的目标元素更改里面的内容。