Vue2
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue响应式原理</title>
</head>
<body>
<div id="app">
<h1 v-text="name"></h1>
<h1 v-text="age"></h1>
<input v-model="input" type="text">
</div>
<script>
const Dep = {
map: {},
collect (propName, cb) {
if (!this.map[propName]) this.map[propName] = []
this.map[propName].push(cb)
},
trigger (propName) {
this.map[propName].forEach(cb => cb())
}
}
function reactiveData(data, key, value) {
Object.defineProperty(data, key, {
get () {
return value
},
set (val) {
value = val
Dep.trigger(key)
}
})
}
let data = {
name: '',
age: 26,
input: 'hello'
}
for (let k in data) {
reactiveData(data, k, data[k])
}
function compiler () {
const childNodes = Array.from(document.querySelector('#app').childNodes).filter(node => node.nodeType === 1)
childNodes.forEach(node => {
const attrs = Array.from(node.attributes)
attrs.forEach(attr => {
const k = attr.nodeName
const v = attr.nodeValue
if (k === 'v-text') {
node.innerText = data[v]
Dep.collect(v, () => {
node.innerText = data[v]
})
}
if (k === 'v-model') {
node.value = data[v]
node.addEventListener('input', e => {
data[v] = e.target.value
})
Dep.collect(v, () => {
node.value = data[v]
})
}
})
})
}
compiler()
</script>
</body>
</html>
Vue3
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.7/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="tel">
<h1 v-text="tel"></h1>
<p v-text="name"></p>
</div>
<script>
let Dep = {
map: {},
collect (key, fn) {
if (!this.map[key]) this.map[key] = []
this.map[key].push(fn)
},
trigger (key) {
this.map[key].forEach(fn => fn())
}
}
let data = {
tel: '178',
name: 'zhaoji'
}
let dataProxy = new Proxy(data, {
set(target, key, val) {
target[key] = val
Dep.trigger(key)
},
get(target, key) {
return target[key]
}
})
function compiler(){
const childnodes = Array.from(document.querySelector('#app').childNodes).filter(node => node.nodeType === 1)
childnodes.forEach(node => {
const attrs = Array.from(node.attributes)
attrs.forEach(attr => {
const attrName = attr.nodeName
const attrValue = attr.nodeValue
if (attrName === 'v-text') {
node.innerText = dataProxy[attrValue]
Dep.collect(attrValue, () => {
node.innerText = dataProxy[attrValue]
})
}
if (attrName === 'v-model') {
node.value = dataProxy[attrValue]
node.addEventListener('input', e => {
dataProxy[attrValue] = e.target.value
})
Dep.collect(attrValue, () => {
node.value = dataProxy[attrValue]
})
}
})
})
}
compiler()
</script>
</body>
</html>