欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Vue源码分析-MVVM实现原理

程序员文章站 2022-03-05 22:12:13
...

什么是MVVM

MVVM是Model-View-ViewModel的简写。即模型-视图-视图模型。

  • 模型指的是后端传递的数据。
  • 视图指的是所看到的页面。
  • 视图模型是mvvm模式的核心,它是连接view和model的桥梁。它能够将数据转化为视图,也能将视图转化为模型,其中视图与模型是不能直接进行通信。
  • ViewModel通过DOM事件监听视图数据的变化,一旦数据发生改变则更新model数据; Model通过数据绑定机制,将数据渲染到视图的Dom上,从而实现了数据的双向绑定。

Vue源码分析-MVVM实现原理
参考:
http://baijiahao.baidu.com/s?id=1596277899370862119&wfr=spider&for=pc
https://segmentfault.com/a/1190000018399478
https://www.cnblogs.com/gaosong-shuhong/p/9253973.html

Vue中的MVVM实现原理

一、数据劫持-
1、Object.defineProperty(obj, key, atts)
在创建Vue实例的时候,通过data属性来管理数据:

new Vue({
  el: "#app",
  data:{
  }
});

然后使用Object.defineProperty(obj, key, atts)方法来对data进行get和set操作。例如:

Object.keys(data).forEach(key => {
    // 开始劫持
	Object.defineProperty(obj, key, {
	       enumerable: true,
	       configurable: true,
	       get() { // 当取值时,触发get方法
	           return value;
	       },
	       set(newValue) { // 给对象赋值的时候,触发set方法
	         console.log(newValue)
	       }
	})
});

以上方法就是对data对象的所有属性进行劫持,当取值的时候,触发get方法,当赋值的时候触发set方法,这样就可以在get和set方法中添加一些逻辑处理。

2、vue源码中的数据劫持
vue源码中的数据劫持在目录/src/core/observer/index.js中的Observerclass类里,在调用walk函数时,调用defineReactive函数,代码如下:

Object.defineProperty(obj, key, {
  enumerable: true,
  configurable: true,
  get: function reactiveGetter () {
    const value = getter ? getter.call(obj) : val
    if (Dep.target) {
      dep.depend()
      if (childOb) {
        childOb.dep.depend()
        if (Array.isArray(value)) {
          dependArray(value)
        }
      }
    }
    return value
  },
  set: function reactiveSetter (newVal) {
    const value = getter ? getter.call(obj) : val
    /* eslint-disable no-self-compare */
    if (newVal === value || (newVal !== newVal && value !== value)) {
      return
    }
    /* eslint-enable no-self-compare */
    if (process.env.NODE_ENV !== 'production' && customSetter) {
      customSetter()
    }
    // #7981: for accessor properties without setter
    if (getter && !setter) return
    if (setter) {
      setter.call(obj, newVal)
    } else {
      val = newVal
    }
    childOb = !shallow && observe(newVal)
    dep.notify()
  }

二、绑定el和编译模板以及指令
在使用vue的时候,创建vue实例会绑定el元素节点:

new Vue({
  el: "#app",
  ....
});

在绑定el这个过程的时候,会把id为app的dom节点下的所有dom编译进内存中,然后在内存中解析出相应的指令,替换模板数据,并添加更新数据函数和初始化相应的订阅者。

  • 编译指令和模板的时候,会把data中的数据赋值给DOM
  • 初始化数据后,再为每一个指令或者模板对象初始化观察者,初始化观察者的时候,获取旧值,在获取旧值的时候触发数据劫持的get方法,在get方法中将观察者添加到订阅者的数组中(即是发布观察者),在数据劫持的set方法中,触发订阅,会去执行观察者的更新方法,再执行观察者回调方法,将新值传给编译指令器中,从而达到了数据更新。

三、MVVM原理图
Vue源码分析-MVVM实现原理

MVVM的简单实现

GitHub源码:https://github.com/RenZhongrui/vue-learn/tree/master/001-vue-mvvm

相关标签: Vue MVVM