详解前端框架设计模式之MVVM | 青训营

前言

MVVM(Model-View-ViewModel)是一种前端设计模式,它将应用程序分成三个部分:模型(Model)、视图(View)和视图模型(ViewModel)。这种设计模式有助于实现前端应用程序的解耦和可维护性。

概念

下面是 MVVM 的基本概念:

  1. 模型(Model):模型是应用程序的数据部分,包含了应用程序的数据和业务逻辑。模型通常通过 AJAX 请求与后端进行交互,以获取或更新数据。
  2. 视图(View):视图是用户界面的一部分,负责呈现模型数据。视图通常是用 HTML 和 CSS 编写的,可以使用模板引擎来渲染动态数据。
  3. 视图模型(ViewModel):ViewModel 是连接模型和视图的桥梁,它负责将模型数据映射到视图上,并将用户的交互事件传递给模型。ViewModel 可以使用数据绑定来自动更新视图,当模型数据发生变化时,视图将自动更新。

在 MVVM 中,最重要的部分是数据绑定和双向数据绑定。数据绑定是指将视图中的元素绑定到模型数据的过程,当模型数据发生变化时,视图将自动更新。双向数据绑定是指同时将视图中的元素绑定到模型数据,并将模型数据绑定到视图中的元素,当视图或模型中的数据发生变化时,另一个部分将自动更新。

MVVM 的实现方式有很多种,其中最流行的是 KnockoutJSVue.js。KnockoutJS 是一个轻量级的 JavaScript 库,它提供了强大的数据绑定功能,可以轻松地将 HTML 元素与 JavaScript 对象进行绑定。Vue.js 是一个流行的前端框架,它也提供了 MVVM 的实现,并具有许多其他功能,如组件化、路由、状态管理等。

除了 KnockoutJS 和 Vue.js,还有其他实现 MVVM 的前端框架和库,如 AngularJS、Backbone.js 等。这些框架和库都提供了不同的方法和工具,以帮助开发人员构建可维护和可扩展的前端应用程序。

现在我们就借鉴vue2的前提下,来谈谈简易版的vue的MVVM中的VM.

VM核心模块

在 Vue2 中,"VM" 并不是一个单独的核心模块或概念,而是指的是 MVVM(Model-View-ViewModel)设计模式的一部分,其中 "VM" 代表 ViewModel。ViewModel 在 Vue.js 中是连接 Model(数据)和 View(视图)的核心部分,它负责处理数据转换、状态管理以及与视图的交互逻辑。

尽管 Vue.js 并没有单独称之为 "VM 模块",但是 Vue 的整体架构中涵盖了 ViewModel 的相关功能。以下是 Vue.js 中涉及 ViewModel 功能的一些核心模块和概念.

响应式

数据双向绑定

Vue.js 是一个用于构建用户界面的 JavaScript 框架。在 Vue.js 中,数据双向绑定是指将数据和视图连接起来,使得当数据发生改变时,视图也会自动更新,反之亦然。

Vue.js 中的双向数据绑定使用了一种叫做数据劫持(data hijacking)的机制。它通过使用 Object.defineProperty() 方法来拦截数据的读取和设置操作,从而实现了数据的双向绑定。

在 Vue.js 中,双向绑定主要通过 v-model 指令来实现。v-model 指令可以将表单输入元素(如文本框、单选框、复选框等)与 Vue 实例中的数据进行绑定。当用户在表单输入元素中输入或修改数据时,Vue 实例中的数据也会自动更新。

除了 v-model 指令,Vue.js 还提供了一些其他的双向绑定指令,如 v-bind 指令,可以将 HTML 属性与 Vue 实例中的数据进行绑定。

除了指令之外,Vue.js 还提供了一些数据绑定的高级功能,如计算属性(computed properties)和观察者(watchers),可以更灵活地处理数据和视图的双向绑定。

总之,Vue.js 中的双向数据绑定是一种非常强大的功能,可以大大简化前端开发的工作。

xml 复制代码
  <div id="app"></div>
  <input type="text" id="input">
  <script>
    let val = ''
    let obj = {}
    Object.defineProperty(obj,'msg',{
      set:function(newVal){
        console.log('handle setter!');
        // 数据变动,更新视图
        document.querySelector('#app').innerHTML = newVal
        val = newVal
      },
      get:function(){
        console.log('handle getter!');
        return val
      }
    })
    // 监听input事件
    document.querySelector("#input").addEventListener('input',function(e){
      obj.msg = e.target.value
    })
  </script>

观察者模式(发布订阅模式)

Vue2在其数据绑定和状态管理中使用了观察者模式的概念,尤其是在实现响应式数据和侦听属性变化方面。观察者模式是一种软件设计模式,用于对象之间的一对多依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。在 Vue2中,这种模式的实现使得数据的变化能够自动反映在用户界面中。

下述代码是关于观察者模式的使用小示例:

xml 复制代码
<button onclick="sell()">大甩卖</button>
  <script>
    function EventHandle(){
      var subs = []
      // 添加需要执行的函数
      this.addSub = function(sub){
        sub && subs.push(sub)
      }
      // 遍历通知
      this.notify = function(){
        subs.forEach(function(sub){
          sub.update()
        })
      }
    }

    var ec = new EventHandle()

    function sell(){
      console.log('开卖!');
      ec.notify()
    }
    // 订阅者
    (function peopleOne(){
      ec.addSub({
        update: function(){
          console.log('peopleOne接收到开卖消息了!');
        }
      })
    })();
    // 2
    (function peopleTwo(){
      ec.addSub({
        update: function(){
          console.log('peopleTwo接收到开卖消息了!');
        }
      })
    })()
  </script>

模板解析

在下述代码中,模板中的双花括号 {{ message }} 表示数据绑定,它会将 Vue 实例的 message 属性的值显示在页面上。 @click 是一个事件指令,当按钮被点击时,会触发 Vue 实例中的 updateMessage 方法。

xml 复制代码
<div id="app">
  <p>{{ message }}</p>
  <button @click="updateMessage">Update Message</button>
</div>
<script>
new Vue({
  el: '#app',
  data: {
    message: 'Hello, Vue!'
  },
  methods: {
    updateMessage() {
      this.message = 'Updated message!';
    }
  }
});
</script>

当 Vue 实例开始解析模板时,它会进行以下步骤:

  1. 模板编译: Vue 将模板解析为虚拟DOM(VNode)表示。在编译过程中,模板中的指令和表达式会被解析成相应的渲染函数。
  2. 渲染函数生成: 通过编译后的虚拟DOM,Vue 生成一个渲染函数,这个函数用于生成实际的DOM元素树。
  3. 初次渲染: Vue 实例首次渲染时,会调用生成的渲染函数,将生成的DOM元素插入到页面中。
  4. 数据响应: Vue 实例的响应式数据变化时,Vue 会重新调用渲染函数来更新DOM元素,实现视图的实时更新。

这种模板解析的方式在开发中带来了很多优势,如:

  • 声明式代码: 模板语法更接近于自然语言,使得开发者可以更专注于界面的描述。
  • 数据绑定: 数据绑定能够自动将数据的变化反映到DOM中,实现视图和数据的同步。
  • 指令: Vue提供了丰富的指令,如条件渲染、循环渲染、事件处理等,使得界面逻辑更容易表达。
  • 模块化: 可以将一个页面拆分成多个可复用的组件,使得代码更模块化和可维护。

需要注意的是,Vue.js 2.x 在模板解析方面的性能已经得到了很大的优化,但在极端复杂的情况下,仍可能影响性能。在这种情况下,可以考虑使用手动渲染和组件的方式来优化性能。

虚拟DOM

在 Vue.js 2 中,虚拟DOM(Virtual DOM)是一个核心概念,它是用来描述界面元素的一种数据结构,以 JavaScript 对象的形式表示。Vue 使用虚拟DOM来提高渲染性能和优化页面更新的效率。

虚拟DOM充当了真实DOM的抽象层,通过将页面的状态映射到虚拟DOM树,Vue可以在需要更新页面时,将虚拟DOM与前一个状态的虚拟DOM进行比较,并且只对真实DOM进行必要的更改,从而减少DOM操作次数,提高渲染性能。

虚拟DOM树由VNode(虚拟节点)构成,VNode是一个用于描述DOM元素的JavaScript对象,包括标签名、属性、子节点等信息。Vue中的VNode对象可以手动创建,也会在模板解析过程中自动生成。

Vue通过使用Diff算法,比较前后两个状态的虚拟DOM树的差异,然后根据差异来更新真实的DOM。这种方式可以避免无效的DOM操作,提高了页面的渲染性能。

Vue的虚拟DOM更新是异步的,它会将多个数据变更合并为一个更新,然后一次性进行DOM操作。这样做可以减少DOM操作的次数,从而提高性能。

在Vue的模板编译过程中,模板会被转化为一个渲染函数,该渲染函数会返回一个VNode树。当状态发生变化时,Vue会调用渲染函数生成新的VNode树,然后与之前的VNode树进行比较,计算出需要更新的部分。

MVVM优缺点

优点

  1. 关注点分离: MVVM模式通过明确的分层将数据、用户界面和业务逻辑分离开来。这有助于提高代码的可维护性和可测试性,使开发人员可以更容易地修改、扩展和维护不同的部分。
  2. 代码重用: ViewModel 可以根据不同的视图需求进行调整,从而实现业务逻辑的重用。这允许您在不同的视图之间共享相同的 ViewModel。
  3. 团队协作: MVVM模式的分层结构可以使不同的团队成员(如设计师、前端开发者、后端开发者)在不同的层次上独立工作,减少了彼此的依赖性。
  4. 可维护性: 由于数据逻辑和展示逻辑分开,所以对逻辑的修改和调试不会影响用户界面的呈现。
  5. 数据绑定: MVVM模式通常具有双向数据绑定的功能,使数据与视图保持同步,从而实现了更实时的用户体验。
  6. 响应式编程: MVVM模式通常涉及响应式编程范式,使数据的变化能够自动传播到相关的视图中。

缺点

  1. 复杂性: MVVM模式引入了额外的层次和概念,可能会增加项目的初始学习成本,特别是对于初学者来说。
  2. 性能: 在某些情况下,MVVM模式可能引入额外的性能开销,特别是在实现数据绑定和观察者模式时。虽然现代前端框架通常会优化这些问题,但仍然需要小心考虑性能问题。
  3. 过度工程: 在小型应用中,采用MVVM模式可能会导致过度设计,增加不必要的复杂性。
  4. 状态管理: 在一些复杂的应用中,随着视图和数据逻辑的增加,可能会涉及到复杂的状态管理问题。如果不恰当地管理好状态,可能会导致应用变得难以理解和维护。

总结

在 MVVM 中,开发人员可以更好地分离关注点,将业务逻辑与用户界面分离,使得代码更容易维护和测试。此外,MVVM 框架通常提供了许多工具和功能,如自动数据绑定、表单验证、路由等,这些功能可以加速前端开发过程,减少重复工作。

虽然 MVVM 是一种流行的前端设计模式,但它并不是唯一的设计模式。还有其他的设计模式和架构,如 MVP(Model-View-Presenter)、MVW(Model-View-Whatever)等。不同的设计模式和架构都有各自的优点和适用场景,开发人员需要根据具体的项目需求和技术选型来选择最适合的设计模式和架构。

总之,MVVM模式通过分离关注点、实现数据绑定等方式提供了很多优点,使前端开发更加有条理。然而,在选择是否使用MVVM模式时,需要根据项目的规模、复杂性和团队的技能来进行权衡,确保它对项目的价值大于其带来的复杂性。🚀🚀🚀🚀🚀

操千曲而后晓声,观千剑而后识器!

相关推荐
千慌百风定乾坤15 小时前
Go 语言入门指南:基础语法和常用特性解析(下) | 豆包MarsCode AI刷题
青训营笔记
FOFO16 小时前
青训营笔记 | HTML语义化的案例分析: 粗略地手绘分析juejin.cn首页 | 豆包MarsCode AI 刷题
青训营笔记
滑滑滑2 天前
后端实践-优化一个已有的 Go 程序提高其性能 | 豆包MarsCode AI刷题
青训营笔记
柠檬柠檬3 天前
Go 语言入门指南:基础语法和常用特性解析 | 豆包MarsCode AI刷题
青训营笔记
用户967136399653 天前
计算最小步长丨豆包MarsCodeAI刷题
青训营笔记
用户52975799354723 天前
字节跳动青训营刷题笔记2| 豆包MarsCode AI刷题
青训营笔记
clearcold4 天前
浅谈对LangChain中Model I/O的见解 | 豆包MarsCode AI刷题
青训营笔记
夭要7夜宵4 天前
【字节青训营】 Go 进阶语言:并发概述、Goroutine、Channel、协程池 | 豆包MarsCode AI刷题
青训营笔记
用户336901104444 天前
数字分组求和题解 | 豆包MarsCode AI刷题
青训营笔记
dnxb1234 天前
GO语言工程实践课后作业:实现思路、代码以及路径记录 | 豆包MarsCode AI刷题
青训营笔记