智能助手 

外观
约 682 字大约 2 分钟
2024-07-28
class Vue {
constructor(options) {
this.$options = options;
this.$el = document.querySelector(options.el);
this.$data = options.data;
this.$node = options.node;
this.init();
return this;
}
init() {
proxyData(this.$data);
defineReactive(this.$data, this);
const watcher = new Watcher();
render2Dom(this.$node, this.$el, this);
}
}
function proxyData(vm, key) {
Object.defineProperty(vm, key, {
get() {
return vm.$data[key];
},
set(newVal) {
vm.$data[key] = newVal;
},
});
}
// 将数据变成响应式
function defineReactive(data, vm) {
const keys = Object.keys(data);
keys.forEach((key) => {
proxyData(vm, key);
const property = Object.getOwnPropertyDescriptor(data, key);
const setter = property && property.set;
const getter = property && property.get;
let val;
if (!getter || setter) {
val = data[key];
}
const dep = new Dep();
Object.defineProperty(data, key, {
get() {
const value = getter ? getter.call(obj) : val;
if (Dep.target) {
dep.depend();
}
return value;
},
set(newVal) {
const value = getter ? getter.call(obj) : val;
if (newVal === value || (newVal !== newVal && value !== value)) {
return;
}
if (getter && !setter) return;
if (setter) {
setter.call(data, newVal);
} else {
val = newVal;
}
dep.notify(vm);
},
});
});
}
function render2Dom(node, parent, vm) {
const fragment = document.createDocumentFragment();
const curEl = document.createElement(node.tag);
if (node.style) {
node.style.forEach((item) => {
curEl.style[item.key] = item.value;
});
}
if (node.textNode) {
let textNode;
if (typeof node.textNode === "string") {
textNode = document.createTextNode(node.textNode);
} else {
textNode = document.createTextNode(vm.$data[node.textNode.value]);
}
curEl.appendChild(textNode);
}
fragment.appendChild(curEl);
if (node.childrenEl) {
node.childrenEl.forEach((item) => {
render2Dom(item, curEl, vm);
});
}
parent.appendChild(fragment);
}
class Watcher {
constructor() {
Dep.target = this;
this.deps = []; // watcher
}
addDep(dep) {
this.deps.push(dep);
dep.addSub(this);
}
update(vm) {
vm.$el.innerHTML = "";
render2Dom(vm.$node, vm.$el, vm);
}
}
// watcher 里收集 dep(sub目标), dep里收集订阅者(watcher)
class Dep {
static target; // watcher
constructor() {
this.subs = [];
}
depend() {
if (Dep.target) {
Dep.target.addDep(this);
}
}
notify(vm) {
this.subs.forEach((item) => {
item.update(vm);
});
}
addSub(watcher) {
this.subs.push(watcher);
}
}
mini-vue
javascript模块中,调用mini-vue的代码是从132行起,前面的是定义mini-vue
<div id="app"></div>
// 定义mini-vue
class Vue {
constructor(options) {
this.$options = options;
this.$el = document.querySelector(options.el);
this.$data = options.data;
this.$node = options.node;
this.init();
return this;
}
init() {
proxyData(this.$data);
defineReactive(this.$data, this);
const watcher = new Watcher();
render2Dom(this.$node, this.$el, this);
}
}
function proxyData(vm, key) {
Object.defineProperty(vm, key, {
get() {
return vm.$data[key];
},
set(newVal) {
vm.$data[key] = newVal;
},
});
}
// 将数据变成响应式
function defineReactive(data, vm) {
const keys = Object.keys(data);
keys.forEach((key) => {
proxyData(vm, key);
const property = Object.getOwnPropertyDescriptor(data, key);
const setter = property && property.set;
const getter = property && property.get;
let val;
if (!getter || setter) {
val = data[key];
}
const dep = new Dep();
Object.defineProperty(data, key, {
get() {
const value = getter ? getter.call(obj) : val;
if (Dep.target) {
dep.depend();
}
return value;
},
set(newVal) {
const value = getter ? getter.call(obj) : val;
if (newVal === value || (newVal !== newVal && value !== value)) {
return;
}
if (getter && !setter) return;
if (setter) {
setter.call(data, newVal);
} else {
val = newVal;
}
dep.notify(vm);
},
});
});
}
function render2Dom(node, parent, vm) {
const fragment = window.document.createDocumentFragment();
const curEl = window.document.createElement(node.tag);
if (node.style) {
node.style.forEach((item) => {
curEl.style[item.key] = item.value;
});
}
if (node.textNode) {
let textNode;
if (typeof node.textNode === "string") {
textNode = window.document.createTextNode(node.textNode);
} else {
textNode = window.document.createTextNode(vm.$data[node.textNode.value]);
}
curEl.appendChild(textNode);
}
fragment.appendChild(curEl);
if (node.childrenEl) {
node.childrenEl.forEach((item) => {
render2Dom(item, curEl, vm);
});
}
parent.appendChild(fragment);
}
class Watcher {
constructor() {
Dep.target = this;
this.deps = []; // watcher
}
addDep(dep) {
this.deps.push(dep);
dep.addSub(this);
}
update(vm) {
vm.$el.innerHTML = "";
render2Dom(vm.$node, vm.$el, vm);
}
}
// watcher 里收集 dep(sub目标), dep里收集订阅者(watcher)
class Dep {
static target; // watcher
constructor() {
this.subs = [];
}
depend() {
if (Dep.target) {
Dep.target.addDep(this);
}
}
notify(vm) {
this.subs.forEach((item) => {
item.update(vm);
});
}
addSub(watcher) {
this.subs.push(watcher);
}
}
// 调用mini-vue
const app = new Vue({
el: "#app",
node: {
tag: "div",
style: [
{
key: "color",
value: "red",
},
],
textNode: "这是一个静态标签div",
childrenEl: [
{
tag: "p",
style: [
{
key: "color",
value: "green",
},
],
textNode: { value: "msg" },
childrenEl: null,
},
{
tag: "p",
style: [
{
key: "color",
value: "blue",
},
],
textNode: { value: "msg2" },
childrenEl: null,
},
],
},
data: {
msg: 1,
msg2: "这是第二个p标签",
},
});
const timer = setInterval(() => {
if (app.msg < 10) {
app.msg++;
} else {
clearInterval(timer);
}
}, 2000);
版权归属:tuyongtao1