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