MVVM
2024年11月17日大约 3 分钟
简介
MVVM是Model-View-ViewModel 的缩写,是一种软件架构模式,通常用于构建用户界面
- Model(模型/数据):模型代表应用程序的数据和业务逻辑。在这一层,数据被封装成对象或数据结构,用于表示应用程序的状态
- View(视图):视图是用户界面的呈现层,负责将模型的数据展示给用户,并接收用户的输入
- ViewModel(视图模型):视图模型是连接视图和模型的中间层。它负责处理视图的显示逻辑,将模型中的数据转换为视图所需的格式,并处理用户输入。视图模型通常实现了一个双向绑定机制,使得视图的变化能够自动反映到模型中,而模型的变化也能够自动更新到视图中
核心思想:将界面的逻辑和数据与界面本身分离,使得界面的开发更加灵活和可维护
VUE文档:虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发
示例图

VM实例
<div id="app"></div>
<script>
const vm = new Vue({
el: "#app",
data: {
text: "hello world"
}
});
</script>
在控制台中或者使用js可以通过 vm.xxx
获取响应的内容,如(控制台):
> vm.$el # 输入
<· <div id="app"></div> # 输出
通过 vm.$el
获取绑定的元素
vue实例属性很多有以 $
开始的和以 _
开始的
- 所有以
$
开始的属性,可以看做是公开的属性,这些属性是供程序员使用的 - 所有以
_
开始的属性,可以看做是私有的属性,这些属性是Vue框架底层使用的
小知识 - Object.defineProperty方法
// 空对象
let app = {};
// 往对象中添加属性 | 往那个对象中添加属性-添加什么属性名-具体的操作
Object.defineProperty(app, "name", {
// 添加的属性值
value: "张三",
// 是否可以被修改
writable: true,
// 当使用属性是调用 —— 当要使用下面的操作时上面两个属性不能有
get: () => {
return this.name;
},
// 当修改属性时调用
set: (val) => {
this.name = val;
}
})
以上代码在调用的时候可能会报出
栈空间溢出
,解决方法定义一个中间变量
数据代理机制
在打印vue实例的时候会出现在 data
中的数据,这是因为vue会代理 data
中的数据,直接通过实例访问其实就是简介的访问 data
中的数据,以下是示例代码:
// 源数据
let app = {
name: "张三"
};
// 代理对象
let appProxy = {};
// 代理name属性
Object.defineProperty(appProxy, "name", {
get: () => {
return app.name;
},
set: (val) => {
app.name = val;
}
})
动态代理:通过访问代理对象的属性来简介访问目标对象的属性,数据代理实现依靠
Object.defineProperty
Vue不会给以 $
或 _
开头的数据做代理,如:
data: {
_a: {},
$b: {}
}
vue数据代理部分实现
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
)
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部分实现
class MyVue {
// 构造函数
constructor(options) {
// ...
// 获取所有方法名
Object.keys(options.methods).forEach((key, index) => {
// 给当前的实例扩展方法
this[key] = options.methods[key]
})
}
}