Skip to content

Instantly share code, notes, and snippets.

@teal-front
Last active August 9, 2023 02:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save teal-front/951e7adfc37bc2e4e118880166f919ce to your computer and use it in GitHub Desktop.
Save teal-front/951e7adfc37bc2e4e118880166f919ce to your computer and use it in GitHub Desktop.
Vue

Vuejs

  1. 虚拟 DOM,用 Js 对象来创建虚拟 DOM,操作虚拟 DOM 比实际 DOM 要快。更快的比较数据变化,更小改变实际 DOM 的改变。

    https://segmentfault.com/a/1190000008291645 剖析 Vue.js 内部运行机制: https://juejin.im/book/5a36661851882538e2259c0f 2-way binding: https://juejin.im/entry/589ff26486b599006b3dea9b

diff 算法:DFS(深度优先搜索),https://foio.github.io/virtual-dom/

  1. Object.freeze可用于中断数据双向绑定
  2. Vue 会高效复用元素,所以有时重新渲染时,元素标签相同而没有重新渲染,使得保留了之前的值,比如 input 标签,这时可以在元素上添加不同的[key=$uuid]属性来强制重新渲染. https://cn.vuejs.org/v2/guide/conditional.html#%E7%94%A8-key-%E7%AE%A1%E7%90%86%E5%8F%AF%E5%A4%8D%E7%94%A8%E7%9A%84%E5%85%83%E7%B4%A0
/**
* mini mock of vue.js
*/
class Watcher {
constructor(cb) {
Dep.target = this;
}
update() {
console.log("update");
}
}
class Dep {
constructor() {
this.subs = [];
}
notify() {
this.subs.forEach(sub => {
sub.update();
});
}
add(watcher) {
this.subs.push(watcher);
}
}
function observe(data) {
Object.keys(data).forEach(key => {
defineReactive(data, key, data[key]);
});
}
function defineReactive(obj, key, value) {
let dep = new Dep();
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
// get 是在什么时候添加的
get() {
dep.add(Dep.target);
return value;
},
set(newValue) {
if (newValue === value) {
return;
}
value = newValue;
dep.notify();
}
});
}
class Vue {
constructor(options) {
this.$data = options.data;
observe(this.$data);
// 只会取最后一个watcher
new Watcher();
}
}
let vm = new Vue({
data: {
foo: "baz"
}
});
// 会注册两次
vm.$data.foo;
vm.$data.foo;
vm.$data.foo = "bar";
let queue = [];
let waiting = false;
class Watcher {
constructor() {}
update() {
queue.push(this);
}
run() {}
}
function queueSch() {}
let callbacks = [];
let pending = false;
function nextTick(cb) {
callbacks.push(cb);
if (!pending) {
pending = true;
setTimeout(flushCallbacks, 0);
}
}
function flushCallbacks() {
let copies = callbacks.slice();
callbacks.length = 0;
copies.forEach(copy => {
copy();
});
pending = false;
}
let w1 = new Watcher();
let w2 = new Watcher();
w1.update();
w2.update();
/**
* vue api: ref,watchEffect
* @doc https://cn.vuejs.org/guide/extras/reactivity-in-depth.html#how-reactivity-works-in-vue
*/
let activeEffect = null;
function track(target, key) {
if (activeEffect) {
const effects = getSubscribers(target, key);
effects.add(activeEffect);
}
}
function trigger(target, key) {
const effects = getSubscribers(target, key);
effects.forEach(effect => effect());
}
// 保存所有的target和key的订阅者
// WeakMap<target, Map<key, Set<effect>>>
// 1. WeakMap的key是弱引用,不会影响垃圾回收
const allTargetMap = new WeakMap();
function getSubscribers(target, key) {
if (!allTargetMap.has(target)) {
allTargetMap.set(target, new Map());
}
const targetMap = allTargetMap.get(target);
if (!targetMap.has(key)) {
targetMap.set(key, new Set());
}
return targetMap.get(key);
}
function watchEffect(effect) {
activeEffect = effect;
effect();
activeEffect = null;
}
function shadowRef (value) {
const refObject = {
get value() {
track(refObject, 'value')
return value
},
set value(newValue) {
value = newValue
trigger(refObject, 'value')
}
}
return refObject;
}
// ------ implement
const count = shallowRef(0);
watchEffect(() => {
console.log(count.value);
});
count.value += 1;
// output: 0 1
// 执行了两次watchEffect,第一次是初始化,第二次是count.value发生变化时
class Mixin {
// 'a.b.c' 对data=obj.a.b, key = 'c'
watch(target, key, callback) {
let segments = key.split('.')
let observer = target
let l = segments.length - 1
for (let i = 0; i < l; i++) {
let segment = segments[i]
if (!(segment in observer)) observer[segment] = {}
observer = observer[segment]
}
let val = observer[segments[l]]
Object.defineProperty(observer, segments[l], {
configruable: true,
enumerable: true,
get() {
console.log(val)
return val
},
set(newVal) {
callback(val, newVal)
val = newVal
}
})
}
}
let mixin = new Mixin()
let data = {
a: {
// b: {
// c: {}
// }
}
}
mixin.watch(data, 'a.b.c', (oldVal, newVal) => {
console.log(oldVal, newVal)
})
data.a.b.c
data.a.b.c = { o: 3 }
// https://github.com/zhangdaren/miniprogram-to-uniapp/blob/80d7302e88dca59748e76002938392b1400f04e1/src/utils/babelUtil.js#L241
function setData(data, key, callback) {
let keys = [];
let val
keys = key.split('.');
val = data[keys[0]]
keys.forEach(function (key2, index) {
if (index + 1 == keys.length) {
console.log(data, key2, val);
} else {
if (!data[key2]) {
console.log(data, key2, {});
}
}
data = data[key2];
});
callback && callback();
}
setData(data, 'a.b.c', () => {
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment