<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<input type="text" v-model="inputValue" />
<input type="text" />
</div>
<script>
// 观察者模式 : 发布者 订阅者
class Dep {
constructor() {
// 订阅者数组
this.watchers = []
}
// 添加订阅者
addWatcher(watcher) {
console.log('添加了:' + watcher)
this.watchers.push(watcher)
}
notify(newValue) {
console.log(this.watchers)
this.watchers.forEach((w) => {
w.upload(newValue)
})
}
}
// 1. const dep = new Dep()
// 2. const w1 = new Wathcer((v) => {console.log(v)});
// 3. dep.addWatcher(w1)
// 4. dep.notify('我发布了新文章')
class Watcher {
constructor(data, key, callback) {
this.callback = callback
// 我们劫持的是 inputValue这个属性 我调用一个 data.inputValue
Dep.target = this
this.value = data[key]
console.log('watcher的构造函数:' + this.value)
}
upload(newValue) {
this.callback(newValue)
}
}
// 接下来 我们自己来实现一个Vue
// 1. 创建一个类
class MyVue {
// 只要外界一旦new,就会执行里面的 constructor方法
constructor({ el, data }) {
// 1. 我先获取到这个容器,绑定在当前实例对象上面
this.container = document.querySelector(el)
// 2. 把当前的data里面的数据 也绑定在 当前实例上面
this.data = data
this.vmData()
this.initInputData()
}
// 2 我需要把data里面的 inputValue的值显示在 页面的input元素上面
initInputData() {
// 记录一下当前的this
const _this = this
// 我要做的事情是 只要有 v-model属性的input元素,要默认显示 data里面的属性
const models = this.container.querySelectorAll('[v-model]')
// 遍历这个数组
models.forEach((element) => {
// 1. 获取到 v-model里面的值,因为这个值就是 data对象里面的属性名
const attr = element.getAttribute('v-model')
element.value = this.data[attr]
// 视图的更新来带动 数据的更新 ,如何知道视图更新了? input事件
element.oninput = function () {
// 只需要在这个地方来进行赋值就好
// 我们data数据是绑定在 vm实例上的
// 这个函数里面this指向 input
_this.data[attr] = this.value
}
const watcher = new Watcher(this.data, attr, (newValue) => {
element.value = newValue
})
})
}
// 数据驱动视图的话 数据劫持 + 观察者模式
// 观察者 监听数据的变化,只要数据变化了,我就通知视图的更新
vmData() {
// 首先要做的是 数据劫持
// Object.defineProperty()
const entries = Object.entries(this.data)
// entries 可以得到对象里面所有的属性,二维数组,数组里面的第一项代表的是 属性名,第二项代表的是属性值
entries.forEach((en) => {
const dep = new Dep()
let rectiveValue = en[1]
// en 是一个数组 ["inputValue","默认值"]
Object.defineProperty(this.data, en[0], {
set(newValue) {
rectiveValue = newValue
console.log('劫持到了数据:' + newValue)
// 只要监听到数据变化,就应该通知 外界
dep.notify(newValue)
},
get() {
console.log(Dep.target)
Dep.target && dep.addWatcher(Dep.target)
console.log('获取到了数据:' + rectiveValue)
return rectiveValue
}
})
})
}
}
const vm = new MyVue({
el: '#app',
data: {
inputValue: '默认值',
inputValue1: '默认值1',
inputValue2: '默认值2'
}
})
</script>
</body>
</html>