Vue初体验之MVC和MVVM

Vue初体验之MVC和MVVM

​ 我们都知道Vue是一个构建数据驱动渐进式框架,渐进式的意思就是在开发过程中根据需要引入三方包,不断完善项目。数据驱动就是数据发生改变,页面自动刷新,也就是数据的双向绑定,响应式。这也是Vue最大的特性和优点之一

​ 那么实现响应式的原理到底是什么呢?本文主要就是概述一下Vue响应式(数据双向绑定)的原理

Vue响应式原理概述(个人见解):

主要是利用了MVVM架构的思想,使用Object.property()数据劫持结合订阅者发布者模式,给Vue中所有的数据添加了get和set方法,视图想要拿数据必须走get方法,拿的是get中的返回值。当数据更新后会自动触发set方法,每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

一、MVC架构思想

上述原理已经说到,Vue响应式原理是基于MVVM架构的思想实现的,但是MVVM又是由MVC衍生而来,所以在此先简述一下MVC的架构思想。

核心思想:代码层次分明,能够清晰明了分离 数据定义层Model ,渲染视图层View,业务逻辑控制层controller

特点:前端的MVC架构并不能简化代码,只是让代码看起来更具有规范性。

Vue初体验之MVC和MVVM_第1张图片

MVC最简代码实现

<body>
    <div class="box">div>

    <script>
        // model:数据模型层,提供数据
        const data = {
            uname: '亚洲舞王赵四'
        }

        // view视图层,渲染页面
        function render(){
            document.querySelector('.box').innerHTML = `

${data.uname}

`
} render(); // controller:控制器层,负责交互行为,修改数据,通知视图层重新渲染页面 function changeUname(){ data.uname = '象牙山小诸葛刘能'; render(); }
script> body>

二、MVVM架构思想

模型层(Model): 负责提供数据

视图层(View): 负责渲染页面

视图模型层(ViewModel):连接模型层和视图层的桥梁

特点: 视图更新 通知 defineProperty 更新数据;数据更新 defineProperty 重新渲染页面

Vue初体验之MVC和MVVM_第2张图片

1、Vue中MVVM的体现

Vue初体验之MVC和MVVM_第3张图片

2、Vue中MVVM底层实现的原理(Object.defineproperty()数据劫持)

js在 Object类提供了一个数据挟持的静态方法 Object.defineProperty()

被挟持的数据 永远不能直接赋值,必须走set 方法

被挟持的数据 获取不到自己的值,获取的是get方法 return 的数据

var data = {
    name:"象牙山小诸葛"
}
//数据挟持,前两个参数分别是要劫持的对象和劫持对象中的属性
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的数据 ====输出'亚洲舞王'

3、最简MVVM代码实现

// 模型层
let data = {
    uname:'象牙山小诸葛'
}

// 视图模型层
let tempUname = data.uname;
Object.defineProperty(data, 'uname', {
    get(){
        // 访问'uname'时触发的方法
        console.log('get');
        return tempUname;
    },
    set(newVal){
        // 修改'uname'时触发的方法
        console.log('set');
        tempUname = newVal;
        render();
    }
})

// 视图层
function render(){
    document.querySelector('#app').innerHTML = `

${data.uname}


${data.uname} οnchange='changeUname(this)' />`
} render(); function changeUname(inp) { console.log(inp.value); data.uname = inp.value; }

4、Vue2.x的坑

上述响应式原理是Vue2.x版本的,这个响应式会有不完美的地方,那就是监听不到对象的新增属性、数组长度以及通过数组下标添加的新元素

vue底层对以下7个方法单独做了新的封装,让通过以下方法修改的数组也可以是响应式的:
push() pop() shift() unshift() splice() sort() reverse()

`解决`:
# 对象的新增属性: 1. this.$set(对象,'属性','值')2. 合并对象:Object.assign({}, 对象, 新增的对象)3. 浅拷贝: {...对象, 属性:值}

# 数组的操作: 1. this.$set(数组, 索引 ,'值'), 2. 七种方法之一

5、Vue3.x的响应式原理

Vue3.x底层利用了Es6的新特性Proxy构造函数来实现数据的响应式,通过Proxy来代理整个数据对象,解决了Vue2.x版本响应式的缺陷

Proxy简易代码实现:Proxy是可以监听到对象的新属性和数组新元素的,下面代码没有写,只是让大家知道Proxy也可以实现数据的响应式

// M: 模型层
let data = {
    uname: '刘能'
}
// VM: 视图模型
let vm = new Proxy(data, {
    get(target, key) {
        // target: 监听的对象
        // key: 对象的属性名
        // 访问了属性时触发的方法

        return target[key]
    },
    set(target, key, newVal) {
        // 修改了属性时触发的方法
        console.log('set');
        target[key] = newVal;
        render();
    }
})
// V: 视图层
function render() {
    let app = document.querySelector('#app');
    app.innerHTML = `

${vm.uname}


${vm.uname} />`
} render(); function changeUname(input) { vm.uname = input.value; }

你可能感兴趣的:(vue.js,经验分享,前端框架)