基于Proxy的双向数据绑定尝试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>基于Proxy的双向数据绑定尝试</title>
</head>
<body>
<div id="root">
名字:<input id="inputName" type="text" oninput="reWrite('name')">
年龄:<input id="inputAge" type="text" oninput="reWrite('age')">
<div id="content">
<p>name: {{name}}</p>
<p>age: {{age}}</p>
</div>
</div>
<script>
let temp = {
name: '王艳军',
age: 21
}
let htmls
// 对模板进行处理后渲染到页面
function render(template, variable) {
// JS编译原理
// 此处省略词素生成器,直接用表达式
const Extractor = /{{(.+)}}/g
let hasNext = true
while (hasNext) {
let res = Extractor.exec(template)
let str, varName
if(res && res.length >= 2) {
str = res[0]
varName = res[1]
console.log(str, varName)
template = template.replace(str, variable[varName])
}else {
hasNext = false
}
}
// 获取作用域,进行代码替换重新渲染
// 此处省略了虚拟DOM中diff算法部分,因为比较麻烦,就直接全替换了
let content = document.getElementById("content")
content.innerHTML = template
// 此处省略v-model写法,其实原理一样,都是编译原理
// 首先js会解析作用域内的代码
// 然后对解析出的代码进行指定语法部分的替换,如{{}}\@click等
// 对一些属性,如v-model\v-bind进行记录,将使用同一变量的进行归类,统一控制
document.getElementById("inputName").value = temp.name
document.getElementById("inputAge").value = temp.age
}
// 代理,实现双向数据绑定的核心
let tempPrpxy = new Proxy(temp, {
set(target, p, value, receiver) {
target[p] = value
// 进行数据重渲染
render(htmls, target)
return true
}
})
// 当数值改变时,先将数据层改变,通过代理重新渲染页面
function reWrite(type) {
let input
if(type === 'name') {
input = document.getElementById("inputName")
}else if(type === 'age') {
input = document.getElementById("inputAge")
}
let value = input.value
tempPrpxy[type] = value
}
function onready() {
// 获取模板
htmls = document.getElementById('content').innerHTML
// 进行第一次渲染
render(htmls,temp)
}
window.onload = onready
</script>
</body>
</html>