MVC与MVVM
# 1.MVC 架构设计思想
核心思想:代码层次分明,能够清晰明了分离 数据定义层Model ,渲染视图层View,业务逻辑控制层controller
特点:前端的MVC架构并不能简化代码,只是让代码看起来更具有规范性。
<div id="app"></div>
1
// 数据层Model 定义数据
const data = {
name: '源码cometang'
}
//视图层 View 渲染视图
function render() {
let app = document.querySelector('#app');
app.innerHTML = `
<p>我的昵称是:${data.name}</p>
<button onclick="editNickeName()">点我修改昵称 </button>
`;
}
//进入页面自动渲染一次
render()
//控制层 controller 改变数据重新渲染视图
function editNickeName() {
//修改数据
data.name = '源码小源'
//重新渲染页面
render()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2.MVVM架构设计思想
MVVM: Model(数据模型) View(视图) ViewModel(视图与数据的双向绑定)
特点: 视图更新 通知 defineProperty 更新数据;数据更新 defineProperty 重新渲染页面
- vue 实现MVVM架构的方式
# 3. Object.defineProperty() 数据挟持
js在 Object类提供了一个数据挟持的静态方法 Object.defineProperty()
被挟持的数据 永远不能直接赋值,必须走set 方法
被挟持的数据 获取不到自己的值,获取的是get方法 return 的数据
Object.defineProperty(挟持的对象,'挟持对象中的属性',{
//获取挟持数据的值时自动触发
get(){
},
//设置 挟持数据的值时自动触发
set(){
}
})
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
var data = {
name:"cometang"
}
//数据挟持
Object.defineProperty(data,'name',{
get(){
console.log('get....');
return '啦啦啦';
},
set(newVal){
console.log('set....',newVal);
}
})
data.name = '小源' //直接赋值失效,把值传给了set方法的newVal
console.log(data.name); //获取值 拿不到对象中的数据,拿到的是 get方法 return的数据 ====输出'啦啦啦'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 4.尝试最简MVVM的实现
写一个最简单的,没有 defineProperty 挟持的 实现 双向绑定的功能【失败】
问题:只实现了 页面变导致数据发生改变,数据变需要重新渲染,在vue代码中可不需要每次更改数据都调用重新渲染页面的函数。
//Model 数据定义
var data = {
name: "cometang"
}
//View 视图渲染
function render() {
let app = document.querySelector('#app');
app.innerHTML = `
<p>
请输入昵称:
<input type="text" onchange="handleChange(this)" value="${data.name}">
</p>
`
}
render(); //初始化渲染
//VM: ViewModel 双向绑定【失败】
//获取页面的最新数据 重新给变量赋值===页面变导致数据变
function handleChange(dom) {
data.name = dom.value;
}
//数据变导致页面变===每次修改数据不能自动更新页面,必须要手动调用render函数
data.name = '小源同学';
//自动渲染失败,只能手动渲染,双向绑定实现失败
render();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 5.通过 defineProperty 实现双向绑定
上述案例 ViewModel 层 没有起到应有的作用,增加defineProperty 挟持
set方法 更新挟持数据:页面变----set自动触发---获取最新数据---更新中间变量的值---重新渲染(自动触发get方法)
get方法 返回最新的中间变量的值------更新挟持的数据的值
//Model 数据定义
var data = {
name: "cometang"
}
//View 视图渲染
function render() {
let app = document.querySelector('#app');
app.innerHTML = `
<p>
请输入昵称:
<input type="text" onchange="handleChange(this)" value="${data.name}">
</p>
`
}
render(); //初始化渲染
//VM: ViewModel 双向绑定
//必须要把 挟持的数据重新存储一份,防止陷入 更新数据的死循环中
let val = data.name;
Object.defineProperty(data, 'name', {
get() {
return val;
},
set(newVal) {
//将最新数据写入到挟持的数据中
val = newVal;
//重新渲染页面
render();
}
})
//获取页面的最新数据 重新给变量赋值===页面变导致数据变
function handleChange(dom) {
data.name = dom.value;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
通过浏览器的控制台 验证
直接输出 data.name 的值 看是否和页面的一致
修改 data.name 之后 页面是否自动发生变化
修改页面的input 框的数据 重新打印 data.name 看是否拿到最新数据
编辑 (opens new window)
上次更新: 2022/06/10, 01:34:10