MVVM是一种双向数据绑定的构架模式,是现在前端非常主流的模式,vue的底层就是通过此实现的

M : model,数据模型,提供数据

V : view,视图,页面展示

VM : viewmodel,试图模型,相当于是M和V之间的桥梁

M到V : 是用到了Object.defineProperty()来挟持data中的数据,把数据转到get和set中操作,每次只要触发set操作修改数据就会更新dom

V到M : 通过事件来监听数据变化,当数据变化时将数据赋给原有数据

后面是示例为准讲一下其中细节:

1.M:声明一个对象,其中一个属性名为params,这给对象obj就相当于model数据模型

// M ==> 数据模型
        let obj = {
            params : 123
        };

2.V:我们获取id名为main的div节点,使用innerHTML在其中创建一个input输入框,将上述的数据params利用模板字符串拼接到innerHTML中,让其渲染到input的value属性中,顺便在input上绑定一个input事件后面要使用,将其封装为函数fn,调用一次实现试图

// V ==> 视图
        function fn(){
            mainNode.innerHTML = `
                <input type="text" value="${obj.params}" oninput="inputNum()">
                <p>${obj.params}</p>
            `
        }
        fn()

3.M ==> V:先实现数据变化时产生渲染效果:

这里利用到Object上的一个方法Object.defineProperty()来挟持数据,其中有三个参数,第一个为所在对象,第二个为挟持属性,第三个为配置项一般为对象,其中包含get和set两个方法,当挟持数据被调用时就会触发get,当数据发生修改时触发set,这里我们将obj.params赋给一个变量num,后再get中返回这个变量,因为如果直接使用obj.params作为返回值的话,一返回就会被当作再次调用obj.params就会进入死循环。

set中有个val为触发set时obj.params变化的值,我们将这个val赋值给变量num后再调用fn函数,注意,这里调用fn函数时函数中会调用obj.params就会再次触发get,后obj.params就将被自动附上返回的变量num的值,前面在set中就给num附上了新值所以现在的obj.params就是最新的值

创建一个按钮,点击触发函数changeNum,其中是将obj.params的值改变,当其一变化就会触发前面的set,执行上述行为

<button onclick="changeNum()">点击修改</button>


<script>
let num = obj.params;
        // VM ==> 试图模型 -- M和V的桥梁
        // M ==>V
        Object.defineProperty(obj , 'params' , {
            get(){
                return num;
            },
            set(val){
                num = val;
                fn();
            },
        })
        function changeNum(){
            obj.params="我改变了"
        }
</script>

4.V==> M:实现试图数据改变原有数据:

 前面在input输入框上绑定input输入事件,让其被触发时就会调用函数inputNum,其是将输入内容赋值给obj.params,所以只要已输入就会触发set,执行set中的赋值渲染操作,实现双向数据绑定

// V ==> M
        function inputNum(){
            obj.params = event.target.value;
        }

 以下为完整代码:

<body>
    <div id="main"></div>
    <button onclick="changeNum()">点击修改</button>

    <script>
        const mainNode = document.querySelector('#main');
        // M ==> 数据模型
        let obj = {
            params : 123
        };
        // V ==> 视图
        function fn(){
            mainNode.innerHTML = `
                <input type="text" value="${obj.params}" oninput="inputNum()">
                <p>${obj.params}</p>
            `
        }
        fn()
        let num = obj.params;
        // VM ==> 试图模型 -- M和V的桥梁
        // M ==>V
        Object.defineProperty(obj , 'params' , {
            get(){
                return num;
            },
            set(val){
                num = val;
                fn();
            },
        })
        function changeNum(){
            obj.params="我改变了"
        }

        // V ==> M
        function inputNum(){
            obj.params = event.target.value;
        }
    </script>
</body>