同事問了這樣一句話,我驚了。
聽說關注我的公眾號的小伙伴,點贊,在看,轉(zhuǎn)發(fā)三連擊的小伙伴鹽值都不錯

今天吃完飯,同事問了我一句話,相當讓我驚訝,你有什么想做卻沒有做的?我說沒有啊,我一直在探索啊,而且我也一直在做我想做的事情,假如我想到了,我可能會花時間去探索,然后如果感覺不適合我,我就放棄。
所以我寫了關于這一系列的 Vue 迷你源碼系列,今天終于是最后一講了,我也不知道是什么樣的動力讓我堅持這么久,我覺得有兩點吧。
第一點:我確實很喜歡寫東西,我小時候就特喜歡寫東西。
第二點:就是為粉絲們做點什么,不能別人關注我,得出一些干貨
喜歡你們多多點贊,關注我,謝謝,如果有需要了解的,可以在后臺跟我留言,或者加我微信跟我探討下,因為微信公眾號不能留言,只能自己自言自語,也不能跟我的粉絲們互動,所以如果有什么想了解的,可后臺留言,平時不忙的話,會回復的。
好了今天就來總結一下之前的所有代碼吧
MVVM 類 Vue 迷你框架(完結撒花)
處理數(shù)據(jù)響應式,分為 代理數(shù)據(jù) 依賴收集 觸發(fā)更新 魔板編譯,解析插值,解析指令,解析事件
完整的代碼如下:
// 數(shù)組響應式處理
// push, pop, reverse, shift, sort, splice, unshift
const arrayMethods = ["push", "pop", "reverse", "shift", "unshift", "sort", "splice"];
const originProto = Array.prototype;
const arrayCopyProto = Object.create(originProto);
arrayMethods.forEach(method => {
arrayCopyProto[method] = function () {
// 原始操作
originProto[method].apply(this, arguments);
// 通知更新操作
}
})
// 響應式數(shù)據(jù)
function defineReactive(obj, key, val) {
observe(val); // 遞歸遍歷
const dep = new Dep(); // 每個key對應創(chuàng)建一個Dep實例
let curVal = val;
Object.defineProperty(obj, key, {
get() {
Dep.target && dep.addDep(Dep.target); // 建立watcher與dep的映射關系
console.log(`get:${key}-${curVal}`);
return curVal;
},
set(newVal) {
if (newVal !== curVal) {
observe(newVal);
console.log(`set:${key}-${newVal}`);
curVal = newVal;
dep.notify(); // 通知更新
}
}
})
}
function observe(obj) {
new Observer(obj);
}
// 屬性代理
function proxy(vm) {
Object.keys(vm.$data).forEach(key => {
Object.defineProperty(vm, key, {
get() {
return vm.$data[key]
},
set(val) {
vm.$data[key] = val
}
})
})
}
// MVue 類
class MVue {
constructor(options) {
this.$options = options;
this.$data = options.data(); // 這里 data 是函數(shù), 所以要執(zhí)行取返回值
// 對 data 選項做響應式處理
observe(this.$data);
// 代理數(shù)據(jù)
proxy(this);
// 編譯模板
new Compile(options.el, this);
}
}
// Observer 用于管理 Watcher
class Observer {
constructor(value) {
this.$value = value
if (Array.isArray(value)) {
// 處理數(shù)組
// array 覆蓋原型,替換變更操作
value.__proto__ = arrayCopyProto;
// 對數(shù)組內(nèi)容元素執(zhí)行響應式
value.forEach(item => observe(item));
}
if (typeof value === 'object') {
// 處理對象
this.walk(value);
}
}
// 遍歷對象,響應式處理
walk(obj) {
Object.keys(obj).forEach(key => defineReactive(obj, key, obj[key]));
}
}
// Compile 編譯類
class Compile {
// 宿主元素
constructor(el, vm) {
this.$el = document.querySelector(el);
this.$vm = vm;
if (this.$el) {
this.compile(this.$el);
}
}
// 判斷節(jié)點是不是含有 {{}} 的文本節(jié)點
isInter(node) {
return node.nodeType === 3 && /{{.+}}/.test(node.textContent);
}
update = (node, key, dir) => {
const fn = this[dir + 'Updater']; // 查找指令
fn && fn(node, this.$vm[key]);
// 更新函數(shù)
new Watcher(this.$vm, key, (val) => {
fn && fn(node, val);
});
}
textUpdater(node, val) {
node.textContent = val;
}
htmlUpdater(node, val) {
node.innerHTML = val;
}
// 插值語法編譯
compileText = (node) => {
let res = /{{(.+)}}/.exec(node.textContent)
console.log("res===>", res)
this.update(node, res[1], 'text');
}
// 遞歸傳入節(jié)點,根據(jù)節(jié)點類型做不同操作
compile = (el) => {
// 拿到子節(jié)點
const childNodes = el.childNodes;
childNodes.forEach(node => {
if (node.nodeType === 1) {
console.log('元素節(jié)點', node.nodeName);
this.compileElement(node);
} else if (this.isInter(node)) {
debugger
this.compileText(node);
console.log('文本節(jié)點', node.textContent);
}
if (node.childNodes) {
this.compile(node);
}
});
}
text = (node, key) => {
this.update(node, key, 'text');
}
html = (node, key) => {
this.update(node, key, 'html');
}
// 節(jié)點元素的編譯
compileElement(node) {
const nodeAttrs = Array.from(node.attributes);
nodeAttrs.forEach(attr => {
const { name, value } = attr;
// 指令處理
if (name.startsWith('m-')) {
const dir = this[name.slice(2)]; // 找出指令方法
dir && dir(node, value);
}
// 事件處理
if (name.startsWith('@')) {
// 找出開頭是 @ 的指令,例如 @click
const dir = name.slice(1);
// 事件監(jiān)聽
this.eventHandler(node, value, dir);
}
})
}
// 綁定監(jiān)聽函數(shù)
eventHandler = (node, value, dir) => {
const { methods } = this.$vm.$options;
const fn = methods && methods[value];
fn && node.addEventListener(dir, fn.bind(this.$vm));
}
// 解析 model
modelUpdater(node, val) {
node.value = val;
}
model = (node, key) => {
this.update(node, key, 'model');
node.addEventListener('input', e => {
this.$vm[key] = e.target.value
});
}
}
// Watcher 類
// 檢測數(shù)據(jù)變化
class Watcher {
constructor(vm, key, updater) {
this.$vm = vm;
this.$key = key;
this.$updater = updater;
Dep.target = this; // 將當前實例指定在Dep的靜態(tài)屬性上
vm[key]; // 讀一下觸發(fā)get
Dep.target = null; // 置空
}
// 未來更新 dom 的函數(shù),由 dep 調(diào)用
update = () => {
this.$updater.call(this.$vm, this.$vm[this.$key])
}
}
// 依賴收集
class Dep {
constructor() {
this.deps = [];
}
addDep = (watcher) => {
this.deps.push(watcher);
}
notify = () => {
this.deps.forEach(watcher => watcher.update())
}
}
評論
圖片
表情
