文章目录
案例
主要实现了v-model
html
<!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>
</head>
<script src="./proxy.js"></script>
<body>
<div id="app">
<div class="item">
<input type="text" placeholder="username_copy" v-model="username">
</div>
<div class="item">
<input type="text" placeholder="username" v-model="username">
</div>
<div class="item">
<input type="text" placeholder="password" v-model="password">
</div>
<hr>
<div class="item">
<p>
username: <span>
{{username}}
</span>
</p>
</div>
<div class="item">
<p>
username_copy: <span>
{{username}}
</span>
</p>
</div>
<div class="item">
<p>
password: <span>
{{password}}
</span>
</p>
</div>
</div>
<button class="btn">修改名字</button>
</body>
<script>
window.onload = function () {
const vm=new Mvvm(document.querySelector("#app"), {
username: "tom",
password: "123456",
})
// 修改data中的数据
document.querySelector(".btn").addEventListener("click",function(){
vm.changeDate("username","小薇")
})
}
</script>
</html>
proxy.js
class Mvvm {
constructor(el, data) {
this.el = el
this.data = data
this.domPool = {} // 收集绑定了对应的data的元素的集合
this.init()
}
init() {
this.bindDom(this.el) // input和文本节点绑定在一起
this.initData() // 将数据转为响应式数据
this.initInput()
}
initData() {
let that = this
this.data = new Proxy(this.data, {
get(target, key) {
return Reflect.get(target, key)
},
set(target, key, val) {
that.domPool[key].forEach(item => { // 数据修改就去修改绑定了对应key的元素的值
if (item.nodeName === "INPUT") {
item.value = val
} else {
item.innerText = val
}
})
return Reflect.set(target, key, val)
}
})
}
initInput() {
let inputs = this.el.querySelectorAll("input")
inputs.forEach(item => {
let mod_key = item.getAttribute("v-model")
if (!this.domPool[mod_key]) {
this.domPool[mod_key] = []
}
this.domPool[mod_key].push(item)
if (mod_key) {
// 对应的input绑定初始值
item.value = this.data[mod_key]
// 这儿用bind 或者使用箭头函数
// 对input绑定事件,当值修改就去修改对应的data中的值
item.addEventListener("keyup",()=>{
this.handleInput( mod_key, item)
})
// item.addEventListener("keyup",
// this.handleInput.bind(this.mod_key, item)
// )
}
})
}
handleInput(key, ele) {
this.data[key] = ele.value
}
bindDom(el) {
let childNodes = el.childNodes
childNodes.forEach(item => {
if (item.nodeType === 3) { // 代表元素或属性中的文本内容。
let val = item.nodeValue.trim() // 拿到具体节点的text
let reg_val=/\{\{(.+?)\}\}/
if (reg_val.test(val)) {
let key = val.match(reg_val)[1]
// console.log(item.parentNode);
if (!this.domPool[key]) {
this.domPool[key] = []
}
this.domPool[key].push(item.parentNode)
item.parentNode.innerText = this.data[key] // 对节点设置初始值
}
}
item.childNodes && this.bindDom(item) // 递归
})
}
changeDate(key = "username", val = "") {
this.data[key] = val
}
}