<!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>
<body>
<div id="app">
<h3 v-html="title"></h3>
<input type="text" v-model="title">
</div>
<script>
// 双向绑定
// 数据源 -- 数据源,尽量的扁平化
var data = {
title: '你好',
user: {
name: 1
}
};
// 对于数据进行观察
observe(data);
// 模板的解析
document.querySelectorAll('[v-html]').forEach(node => {
let key = node.getAttribute('v-html')
node.innerHTML = data[key]
});
document.querySelectorAll('[v-model]').forEach(node => {
let key = node.getAttribute('v-model')
node.value = data[key];
node.addEventListener('input', function () {
data[key] = this.value
}, false)
});
/**
* 数据观察 -- 一定要对象,普通数据不进行观察
*/
function observe(target) {
// 类型判断 必须为对象
// if (typeof target === 'object' && target instanceof Object)
// 原型+冒充 [object Object]
// 如果它不是一个对象,则不进行任务的数据代理 -- 在多层代理时,防递归出不去的情况
if (Object.prototype.toString.call(target) != '[object Object]') return;
// 如果是对象则进行数据代理
// Object.defineProperty,它只能代理对象中的属性
// for in / Object.keys().forEach
for (let key in target) {
// 数据对象的属性代理ss
defineReactive(target, key, target[key])
}
}
// 代理
function defineReactive(target, key, value) {
// 递归 --
observe(value)
Object.defineProperty(target, key, {
get() {
console.log('get')
// 获取数据时触发
return value;
},
set(v) {
if (v != value) {
console.log('set')
// 设置数据时会触发
value = v
updateView(value)
}
}
})
}
function updateView(value) {
document.querySelectorAll('[v-html]').forEach(node => {
let key = node.getAttribute('v-html')
node.innerHTML = value
});
}
</script>
</body>
</html>
6.双向绑定(v-model)的实现
于 2022-07-13 18:08:53 首次发布