欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

理解 Vue 的 MVVM 模式

程序员文章站 2022-03-30 23:10:02
...

MVVM 模式实现

MVVM模式又称双向数据绑定,是数据影响视图,视图影响数据的模式

Vue: 实现方式使用数据劫持+ 发布订阅模式,其核心为 Object.defineProperty 不兼容IE8以下
Angualr:  使用脏值检测
这次主要介绍 Vue 如何通过 Object.defineProperty() 实现 MVVM

Object.defineProperty(obj, ‘propertyName’, {
    value: Value,
    enumerable: boolean, //默认为fasle 其他属性为不可枚举 无法使用for遍历
    configurable: boolean, //默认false时不能进行删除
    writable: boolean, // 默认为false时无法修改
    // 当有writable和value时不可以使用set get
    //获取obj的值时调用
    get() {
        return 'silverwing'
    },
    //当给obj赋值时调用,参数为赋值的参数
    set(val) {
        console.log(val)
    }
})

数据劫持

使用 Object.defineProperty定义所有属性

Vue 实现 MVVM 的方式主要通过data里面的值 递归的进行数据劫持达到深度响应(因为每次赋予一个新对象时会给这个新对象增加数据劫持)

让我们手动模拟这么一个实现过程:
先创建 一个 html(任意名字) 和 mvvm.js 在同一个目录下

先创建 一个 html(任意名字) 和 mvvm.js 在同一个目录下

理解 Vue 的 MVVM 模式

*.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script>
        let obj  = {}
        Object.defineProperty(obj, 'school',{
            value:'silverwing'
        })
        
        delete obj.school
    </script>
</body>
</html>


mvvm.js

function Soyas(options = {}) {
    this.$options = options // 将所有属性挂在在了$options
    // this._data
    var data = this._data = this.$options.data;
    observe(data)
}
function observe(data) {
    if (typeof data !== 'object')
        return new Observe(data)
}
// 观察对象增加Object.defineProperty
function Observe(data) { // 这里写主要逻辑
    for (let key in data) { // 把 data 属性 通过Object.defineProperty方式定义属性
        let val = data[key];
        Object.defineProperty(data, key, {
            enumerable: true,
            get() {
                return val;
            },
            set(newVal) { // 更改值的时候
                if (newVal === val) {
                    // 设置的值和旧值一样的时候
                    return;
                }
                val = newVal; // 如果以后获取值的时候将刚才设置的值放回去
            }
        })
    }
}

控制台查看

理解 Vue 的 MVVM 模式

这样就完成了一个简单的数据劫持

但是任然存在问题

理解 Vue 的 MVVM 模式

当赋予一个对象时候我们仍需要对内部的对象进行数据劫持,以达到深度响应

如果没有进行数据劫持的情况下,属性不具有 set() get() 方法,此时是无法实现数据相应的

function Observe(data) { // 这里写主要逻辑
    for (let key in data) { // 把 data 属性 通过Object.defineProperty方式定义属性
        let val = data[key];
        observe(val); // 添加劫持
        Object.defineProperty(data, key, {
            ...
            set(newVal){
                ...
                observe(newVal) // 返回对象进行劫持
            }
        })
    }
}

再次查看控制台


理解 Vue 的 MVVM 模式


如此即可完成数据的每层对象进行劫持达到深度响应的效果

此时我们还需要做一件事,我们每次通过 soyas._data 这种方式访问并不优雅

我们可以通过数据代理达到 soyas.property 的方式访问

function Soyas(options = {}) {
    ...
    // this 代理了 this._data;
    for (let key in data) {
        Object.defineProperty(this, key, {
            enumerable: true,
            get() {
                return this._data[key];
            },
            set(newVal) {
                this._data = newVal

            }
        })
    }
}

添加完上述代码后


理解 Vue 的 MVVM 模式


Very Good!一切OK

总结:

——Soyas 类内部 通过调用一个 observe 进行数据劫持到达到双向数据绑定

——达到深度响应我们需要在 Observe 遍历数据,和返回新值时候 递归调用 observe,对每一个对象进行数据劫持

——通过对象的内部使用 Object.defineProperty 使用 this 代理 this._data