需求: 使用原生js实现一个v-model的效果
前言: vue中的 v-model是 :value + @input 方法
vue响应式的核心 Object.defineProperty这个方法
思路: Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有 的属性,并返回此对象。
Object.defineProperty 方法 对 data中定义的数据做劫持, 劫持出一个新对象,我们在操作数据的时候其实一直操作的是这个新对象
Object.defineProperty有三个参数:
参数一: 我们要处理的对象
参数二: 这个对象上的属性
参数三: 一个配置对象 其中有get 和 set 方法
get方法实时将我们原有对象的最新状态同步给新对象
set方法当值修改后会触发, 这个方法中可以接收一个参数value=>最新的值, 将这个值同步给我们原有的对象
修改视图的时候, 把值赋给我们新对象对应的属性,触发set方法, 实现数据双向绑定
以下代码:
<h2></h2>
<input></input>
// 获取dom元素
const h2 = document.querySelector('h2')
const ipt = document.querySelector('input')
const obj = {name: 'lisi'}
let _data = {} // vue中模拟我们真实data中的数据 做了一份新的拷贝
// Object.defineProperty() 他的三个参数
// 参数一: 我们要处理的对象
// 参数二: 这个对象上边的属性
// 参数三: 配置对象
Object.defineProperty(_data, 'name', {
get() {
return obj.name // 虚拟数据中实时同步我们原有的数据
},
set(val) {
console.log('属性修改了', val) // 李四
obj.name = val // 只要obj.name发生更改 _data中的name属性也会同步
// 将最新的数据同步给视图
h2.innerHTML = val
ipt.value = val
}
})
console.log(obj)
_data.name = '李四'
console.log(obj)
// 给两个dom元素设置默认内容
h2.innerText = _data.name
ipt.value = _data.name
// 双向绑定 数据驱动视图 视图驱动数据
// 监听input的input事件
ipt.addEventListener('input', (e) => {
console.log(e.target.value)
_data.name = e.target.value
})