Vue: 一个简单的Vue2.0 v-model双向数据绑定的实现,含源代码,小白也能看懂

首先说一下原理吧

      View层(dom元素)的变动如何响应到Model层(Js变量)呢? 通过监听元素的input事件来动态的改变js变量的值,实际上不是改变的js变量的值,而是改变的js变量的getter的返回值

      Model层(Js变量)的变动如何响应到View层(dom元素)呢?通过Object.defineProperty API的set回调方法可以劫持JS变量设置的新值newVal,然后将新值newVal设置给dom元素。

定义我们的view层

<input type="text" v-model="msg"><br>
<input type="text" v-model="msg"><br>
<input type="text" v-model="name">

 

定义我们的model代码  

let data = {
    msg: 'hello',
    name: ''
}

定义我们的核心代码双向数据绑定

// 用户存放状态更改的新值
let reflect = {};
// 用于存放状态到dom元素的映射 也就是key是data里面的属性,value存的是数组domArr,domArr存放的是v-model等于key的元素
let deep = {};
// 查询到所有的含有v-modle属性的dom元素
document.querySelectorAll("[v-model]").forEach(item => {
    // 获得dom元素的v-model的值
    let model = item.getAttribute("v-model");
    // 如果如果值所对应的映射数组为空的话 就初始化
    deep[model] = deep[model] || [];
    // 绑定状态和dom元素的映射关系
    deep[model].push(item)
    // 初始化dom元素的值 和 状态get的值
    reflect[model] = item.value = data[model];
    //监听dom元素的input事件
    item.addEventListener('input', function(){
        // 将dom元素的新值赋值给data中定义的状态
        data[model] = item.value;
    },false)
})
// 循环遍历所有状态
for(let [key, val] of Object.entries(data)){
    // 通过Object.defineProperty来实现监听
    Object.defineProperty(data, key, {
        // 劫持状态更新的新值
        set(newVal){
            // 将更新的新值设置给get的返回值
            reflect[key] = newVal;
            //  循环将更新的新值设置给关联的的dom元素
            deep[key] && deep[key].forEach(item => {
                item.value = newVal;
            })
            return newVal;
        },
        // 返回状态的新值
        get(){
            return reflect[key];
        }
    })
}

此时,无论是改变input的值,还是改变data里面定义的状态,数据都会向另一端同步。

PS:这只是简单的实现了一下v-model,与Vue 2中的实现还是有一些差异的,原理都是相同的。

 

posted @ 2021-06-28 15:11  王阿灿  阅读(260)  评论(1编辑  收藏  举报