整体流程图
在10~15分钟完成的自定义Vue
代码语言:javascript
复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>EasyFrame</title>
<script src="./easy-frame.js"></script>
</head>
<body>
<div id="app">
<p>{{count}}</p>
<button @click="add"> 1</button>
</div>
<script>
const app = new EasyFrame({
el: "#app",
data: {
count: 0,
},
methods: {
add() {
console.log("add");
this.count ;
},
},
});
</script>
</body>
</html>
EasyFrame
代码语言:javascript
复制function EasyFrame(options) {
this.$options = options;
this.$el = this.$options.el;
this.$data = this.$options.data;
this.$methods = this.$options.methods;
observe(this.$data);
proxy(this);
compile(this.$el, this);
}
observe
代码语言:javascript
复制function observe(obj) {
function defineReactive(obj, key, val) {
observe(val);
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
// 绑定后清空target,下个对象响应化时,对应绑定
Dep.target && dep.addDep(Dep.target);
console.log("getter");
return val;
},
set(newVal) {
if (newVal != val) {
console.log("setter");
observe(val);
val = newVal;
dep.notify();
}
},
});
}
Object.keys(obj).forEach((key) => defineReactive(obj, key, obj[key]));
}
compile
代码语言:javascript
复制function compile(el, vm) {
function traverse(nodes) {
nodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
Array.from(node.attributes).forEach((attr) => {
if (attr.name.startsWith("@")) {
const attrName = attr.name.substring(1);
const attrValue = attr.value;
node.addEventListener(attrName, vm.$methods[attrValue].bind(vm));
}
});
}
if (
node.nodeType === Node.TEXT_NODE &&
/{{(.*)}}/.test(node.textContent)
) {
node.textContent = vm[RegExp.$1];
new Watcher(vm, RegExp.$1, function (val) {
node.textContent = val;
});
}
if (node.childNodes && node.childNodes.length > 0) {
traverse(node.childNodes);
}
});
}
const childNodes = document.querySelector(el).childNodes;
traverse(childNodes);
}
Watcher&Dep
代码语言:javascript
复制function Dep() {
this.watchers = [];
this.addDep = function (watcher) {
this.watchers.push(watcher);
};
this.notify = function () {
this.watchers.forEach((watcher) => watcher.update());
};
}
function Watcher(vm, key, fn) {
// 触发依赖收集
Dep.target = this;
vm[key];
Dep.target = null;
// 回调最新val
this.update = function () {
fn && fn(vm[key]);
};
}
proxy
代码语言:javascript
复制function proxy(vm) {
Object.keys(vm.$data).forEach((key) => {
Object.defineProperty(vm, key, {
get() {
return vm.$data[key];
},
set(val) {
vm.$data[key] = val;
},
});
});
}