Skip to content

简介

MVVM是Model-View-ViewModel 的缩写,是一种软件架构模式,通常用于构建用户界面

  • Model(模型/数据):模型代表应用程序的数据和业务逻辑。在这一层,数据被封装成对象或数据结构,用于表示应用程序的状态
  • View(视图):视图是用户界面的呈现层,负责将模型的数据展示给用户,并接收用户的输入
  • ViewModel(视图模型):视图模型是连接视图和模型的中间层。它负责处理视图的显示逻辑,将模型中的数据转换为视图所需的格式,并处理用户输入。视图模型通常实现了一个双向绑定机制,使得视图的变化能够自动反映到模型中,而模型的变化也能够自动更新到视图中

核心思想:将界面的逻辑和数据与界面本身分离,使得界面的开发更加灵活和可维护

VUE文档:虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发

示例图

image-20240406171652650

VM实例

官方API文档

html
<div id="app"></div>
<script>
    const vm = new Vue({
        el: "#app",
        data: {
            text: "hello world"
        }
    });
</script>

在控制台中或者使用js可以通过 vm.xxx 获取响应的内容,如(控制台):

bash
> vm.$el # 输入
<· <div id="app"></div> # 输出

通过 vm.$el 获取绑定的元素

vue实例属性很多有以 $ 开始的和以 _ 开始的

  • 所有以 $ 开始的属性,可以看做是公开的属性,这些属性是供程序员使用的
  • 所有以 _ 开始的属性,可以看做是私有的属性,这些属性是Vue框架底层使用的

小知识 - Object.defineProperty方法

javascript
// 空对象
let app = {};
// 往对象中添加属性 | 往那个对象中添加属性-添加什么属性名-具体的操作
Object.defineProperty(app, "name", {
    // 添加的属性值
    value: "张三",
    // 是否可以被修改
    writable: true,
    // 当使用属性是调用 —— 当要使用下面的操作时上面两个属性不能有
    get: () => {
        return this.name;
    },
    // 当修改属性时调用
    set: (val) => {
        this.name = val;
    }
})

以上代码在调用的时候可能会报出栈空间溢出,解决方法定义一个中间变量

数据代理机制

在打印vue实例的时候会出现在 data 中的数据,这是因为vue会代理 data 中的数据,直接通过实例访问其实就是简介的访问 data 中的数据,以下是示例代码:

javascript
// 源数据
let app = {
    name: "张三"
};
// 代理对象
let appProxy = {};

// 代理name属性
Object.defineProperty(appProxy, "name", {
    get: () => {
        return app.name;
    },
    set: (val) => {
        app.name = val;
    }
})

动态代理:通过访问代理对象的属性来简介访问目标对象的属性,数据代理实现依靠 Object.defineProperty

Vue不会给以 $_ 开头的数据做代理,如:

javascript
data: {
	_a: {},
	$b: {}
}

vue数据代理部分实现

javascript
class MyVue {
    // 构造函数
    constructor(options) {
        // 数据代理 key:键值 index:索引
        Object.keys(options.data).forEach((key, index) => {
            // 不能是以_开头的,不能是$开头的
            if (key.charAt(0) !== '_' && key.charAt(0) !== '$')
                Object.defineProperty(this, key, {
                    get() {
                        return options.data[key]
                    },
                    set(val) {
                        options.data[key] = val
                    }
                });
        })
    }
}

函数中的 this

methods 中使用想要使用 data 中的数据不能够直接使用,需要以 this.x 来进行调用(this == vm

javascript
const vm = new Vue({
    el: "#app",
    data: {},
    methods: {
        test1() {
            console.log(vm == this);
        },
        // 在箭头函数中没有this,它的this是继承的父级的
        // 当前父级就是window
        test2: () => {
            console.log(vm != this);
            console.log(this == window);
        }
    }
})

vue methods部分实现

javascript
class MyVue {
    // 构造函数
    constructor(options) {
        // ...

        // 获取所有方法名
        Object.keys(options.methods).forEach((key, index) => {
            // 给当前的实例扩展方法
            this[key] = options.methods[key]
        })
    }
}