暂时是给自己看的
// 改造数据对象属性
function defineReactive(obj, key, val) {
const dep = new Dep()
Reflect.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function() {
console.log('get: ', val)
if (Dep.target) {
// 手机依赖,等同于 dep.addSub(Dep.target)
dep.depend()
}
return val
},
set: function(newVal) {
console.log('set: ', newVal)
// 判断新值与旧值是否相等
// 判断后半段是为了验证新值与旧值都为NaN的情况
if (newVal === val || (newVal !== newVal && value !== value)) {
return;
}
val = newVal
// 发布改变
dep.notify()
}
})
}
// 删除数组中元素
function remove(arrs, item) {
console.log(arrs, item)
const index = arrs.indexOf(item)
if (index !== -1) {
arrs.splice(index, 1)
}
}
// 依赖收集器
class Dep {
constructor() {
// 订阅的信息
this.subs = []
}
// 添加一个观察者对象
addSub(sub) {
this.subs.push(sub)
}
// 删除一个观察者对象
removeSub(sub) {
remove(this.subs, sub)
}
// 此方法作用等同于 this.subs.push(Watcher)
depend() {
if (Dep.target) {
Dep.target.addDep(this)
}
}
// 发布通知,有更新
notify() {
const subs = this.subs.slice()
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update()
}
}
}
Dep.target = null
// 观察者
class Watcher {
constructor(vm, cb) {
this.vm = vm
this.cb = cb
Dep.target = this
this.value = cb()
}
addDep(dep) {
dep.addSub(this)
}
update() {
if (this.cb) this.cb()
Dep.target = null
}
}
// 双向绑定
class Observer {
constructor(data) {
for (let key in data) {
defineReactive(data, key, data[key])
}
}
}
// 创建 Observer 实例
function observe(data) {
return new Observer(data)
}
// 操作库
class Vue {
constructor(options) {
if (options && typeof options.data === 'function') {
this._data = options.data.apply(this)
}
this._el = options.el
observe(this._data)
}
// 挂载函数
mount() {
new Watcher(this, this.render.bind(this))
}
// 渲染函数
render() {
document.querySelector(this._el).innerHTML = this._data.text
}
}
// demo
const vm1 = new Vue({
el: '#app1',
data() {
return {
text: 'app1'
}
}
})
const vm2 = new Vue({
el: '#app2',
data() {
return {
text: 'app2'
}
}
})
vm1.mount()
vm2.mount()
vm1._data.text = 'app1___'
vm2._data.text = 'app2___'