当前位置: 首页 > news >正文

【Vue】从 MVC 到 MVVM:前端架构演变与 Vue 的实践之路

个人博客:haichenyi.com。感谢关注

一. 目录

  • 一–目录
  • 二–架构模式的演变背景​
  • 三–MVC:经典的分层起点​
  • 四–MVP:面向接口的解耦尝试​
  • 五–MVVM:数据驱动的终极形态​​
  • 六–Vue:MVVM 的现代化实践​​​

二. 架构模式的演变背景​

  在软件开发中,架构模式是解决代码组织,职责分离和可维护行的核心方案。一个"好"的架构可以少很多不必要的麻烦。这个"好"就很关键,虽然架构模式经历了从MVC——>MVP——>MVVM的演变,但是,不一定后者比前者好。比方说:你一个小项目,MVC就够用了,非要去使用MVP,MVVM,就会多写很多无用代码。要结合多方面去考虑。软件开发的终极目标是高类聚,低耦合 。但是,还是需要结合实际项目去选择。18年MVVM刚兴起的时候,就写过一篇三者的区别的文章
MVC、MVP、MVVM比较。回顾了一下,感觉还是适用的。

三. MVC:经典的分层起点

  1. 核心思想
  • Model:管理数据和业务逻辑
  • View:呈现给用户看的界面
  • Controller:接收用户输入,协调Model和View
  1. 典型流程
    2.1 用户点击按钮触发点击事件,传递到Controller
    2.2 Controller触发Model的事件去拿数据
    2.2 Model数据更新之后,通知Controller更新view
//伪代码如下
let tvContent = document.getElementById("tv_content")
document.getElementById("btn").onclick = function () {axios.post().then(res=>{let data = res.datatvContent.textContent = data})
}
//当前页面获取view的某个组件的引用
//用户点击按钮,触发网络请求,拿到数据
//拿到数据之后,更新tvContent的内容
//当前页面就是Controller,网络请求包装的类就是Model,组件就是view
//Controller控制Model,model拿到数据之后控制view刷新界面
//代码少,逻辑简单,看不出来啥问题。挺好用的。但是,代码多,逻辑复杂呢?
//(前面就说了架构要根据实际项目情况来看)
  1. 局限性
  • View和Model直接交互,耦合度高
  • Controller臃肿:业务代码全都写在Controller中

四. MVP:面向接口的解耦尝试​

  1. 核心改进
  • Presenter(协调者):取代Controller,通过接口与view通信
  • View被动化,只负责页面更新,逻辑由Presenter处理
  1. 典型流程
    2.1 View接收用户操作,调用Presenter接口
    2.2 Presenter操作Model处理数据
    2.3 Model返回结果后,Presenter通过View接口更新页面
//伪代码如下,H5没有接口的概念,我都不知道怎么举例子
//这么理解,接口就是定义了一个一个的功能,需要有实现类去实现。
//还是上面的例子:用户点击按钮更新页面
interface IHome {update(content)
}class HomeImpl implements IHome {tvContent;constructor() {this.tvContent = document.getElementById("tv_content")}update(content: string) {this.tvContent.textContent = content}
}class HomePresenter {iHome: IHomeconstructor(iHome: IHome) {this.iHome = iHome}getData() {Axions.post().then(res=>{this.iHome.update(res.data)})}
}
let homePresenter = new HomePresenter(new HomeImpl())
document.getElementById("btn")?.onclick = function () {homePresenter.getData()
}
//上面的IHome接口,就是页面更新的定义,HomeImpl就是这个接口的实现
//如果,页面有很多种显示需要处理,就需要定义多个方法,需要多个实现,以便于后面P层调用
//HomePresenter就是P层,负责数据处理,和使用接口的引用更新页面
//按钮点击,触发P层逻辑。
//这只是最简单的写法,有很多优化点。Android里面用的比较多
  1. 优势与不足
  • 优势:View和Model完全解耦
  • 不足:需要手动维护大量的接口,代码冗余

五. MVVM:数据驱动的终极形态

  1. 核心思想
  • ViewModel:作为view和model的桥梁,通过数据绑定实现自动同步
  • 双向绑定:view的输入自动更新model,model数据变化自动刷新view
  1. 典型流程
    2.1 view通过模板语法(如{{data}}),绑定到ViewModel
    2.2 ViewModel监听到Model变化,并转换为View所需要的数据格式
    2.3 用户操作触发ViewModel的方法,更新Model
//这么举例子呢,其实,万变不离其中,你不做的事情,都是框架帮你做的。
//比方说,Vue的响应式编程,你只用改变数据,页面自动更新。啥都不干,页面怎么可能知道数据遍了,从而自动更新呢?
//实际上就是发布订阅者模式触发更新,那么,是谁发布,谁订阅呢?放到后面第六部分讲
  1. 优势
  • 开发高效​​:减少手动 DOM 操作,聚焦数据逻辑
  • 动态更新​​:适合实时数据展示
  • 缺点:学习成本高,上手慢。原理复杂,遇到问题,不容易定位

六. Vue:MVVM 的现代化实践

先说概念:Vue.js是mvvm模式集大成者,通过响应式系统和申明试模板,简化了数据绑定。并引入组件化解决复杂场景的问题。
6.1 Vue中MVVM的映射关系

MVVM层Vue实现
Modeldata属性
View模板(templtate)和样式(style)
ViewModelVue组件实例(暴露:data,computed,methods)

6.2 双向绑定的原理:Vue 的响应式系统通过以下步骤实现:

  • 数据劫持
    • vue2是使用 Object.defineProperty 监听对象属性。
    • vue3是使用Proxy代理对象,支持深层次监听
// Vue 2 数据劫持示例
function defineReactive(obj, key, val) {Object.defineProperty(obj, key, {get() {dep.depend(); // 收集依赖return val;},set(newVal) {val = newVal;dep.notify(); // 触发更新}});
}	
//这里插一句题外话,这个响应式的设计模式,就是观察者模式
//数据本身就是被观察者,get方法里面收集依赖,就是收集观察者,set方法里面触发更新,就是通知观察者数据发生了变化
//vuex使用的是发布订阅者模式。
//下一篇文章。就讲讲这两种设计模式吧。
  • 依赖收集
    • 每个组件对应一个 ​​Watcher​​,在渲染时访问数据属性,触发 getter 收集依赖。
  • 分发更新
    • 数据修改时触发 setter,通知所有关联的 Watcher 重新渲染(通过虚拟 DOM 对比更新真实 DOM,Diff算法)。

6.3 示例:数据变化驱动视图更新​

<template><div><!-- 双向绑定:v-model 语法糖 --><input v-model="message" /><p>{{ reversedMessage }}</p></div>
</template><script>
export default {data() {return { message: "Hello Vue!" }; // Model},computed: {reversedMessage() { // ViewModel 逻辑return this.message.split('').reverse().join('');}}
}
</script>

Vue 的双向绑定​,解析如下:

HTML 模板

<div id="app"><input v-model="message" /><p>{{ reversedMessage }}</p>
</div>

​JavaScript 逻辑​

// 模拟 Vue 实例
const data = { message: "Hello" };// 1. 数据劫持
defineReactive(data, "message", data.message);// 2. 计算属性(依赖 message)
const computed = {reversedMessage: () => data.message.split("").reverse().join("")
};// 3. 模板渲染 Watcher
new Watcher(() => {//归根结底,页面更新的方法,还是这个。我们前面说的mvc,mvp页面更新也是这个方法//所以,你以为它很神奇,其实,底层原理都是一样的。主要还是看每个人的思路。document.querySelector("p").textContent = computed.reversedMessage();
});// 4. 双向绑定(输入框 → 数据)
document.querySelector("input").addEventListener("input", (e) => {data.message = e.target.value; // 修改数据 → 触发 setter → 更新视图
});

效果​​:

  1. 输入框内容变化时,data.message 更新。
  2. reversedMessage 自动重新计算,p标签内容实时更新。

http://www.mrgr.cn/news/98711.html

相关文章:

  • shell 编程之正则表达式与文本处理器
  • centos7停服yum更新kernel失败解决办法
  • C++中变量、函数存储、包括虚函数多态实现机制说明
  • Deno 统一 Node 和 npm,既是 JS 运行时,又是包管理器
  • chili3d调试笔记2+添加web ui按钮
  • 基础学习:(6)nanoGPT
  • 单片机基础知识-STM32
  • vue3.2 + element-plus 实现跟随input输入框的弹框,弹框里可以分组或tab形式显示选项
  • YOLOV8 OBB 海思3516训练流程
  • 十八、TCP多线程、多进程并发服务器
  • Tomcat与Servlet
  • vmcore分析锁问题实例(x86-64)
  • 面试经历---某能源公司
  • vue动态组件实现动态表单的方法
  • 从标准九九表打印解读单行表达式的书写修炼(Python)
  • 05-DevOps-Jenkins自动拉取构建代码
  • Rust : 关于*const () 与type erase
  • ReportLab 导出 PDF(图文表格)
  • 21天Python计划:零障碍学语法(更新完毕)
  • OSPF综合实验