Vue 项目里怎么用 MVP 模式组织代码?
最近在重构一个 Vue 2 的老项目,想尝试用 MVP(Model-View-Presenter)模式来解耦逻辑,但有点搞不清怎么在 Vue 里合理划分 Presenter 和组件的关系。我试过把业务逻辑抽到单独的 presenter.js 文件里,然后在组件里调用,但感觉数据流变得很乱,响应式也失效了。
比如下面这个简单的用户信息展示组件,我原本希望 Presenter 负责获取和处理数据,View 只负责渲染,但实际写起来发现 Vue 的 data 和 methods 很难完全剥离。是我理解错了 MVP 在 Vue 中的用法吗?
<template>
<div>{{ userInfo.name }}</div>
</template>
<script>
import UserPresenter from './UserPresenter'
export default {
data() {
return { userInfo: {} }
},
created() {
this.userInfo = UserPresenter.getUserInfo()
}
}
</script>
UserPresenter.getUserInfo()这么一调用,拿到的就是个普通对象,跟 Vue 的响应式系统完全脱节,当然就乱了。MVP 在 Vue 里要玩得优雅,关键在于让 Presenter 持有的状态本身是响应式的,或者让 Presenter 有能力触发 View 的更新。
给你一个更优雅的写法,用 Vue 的响应式能力来驱动 Presenter 层:
组件这边就变得很干净了:
这样写有几个好处。数据流很清晰,Presenter 持有状态和业务逻辑,View 只负责渲染和响应用户操作。响应式也正常工作,因为状态本质上是 Vue 实例的 data。测试的时候可以单独测 Presenter,不用挂载组件。
不过说实话,Vue 2 里这么搞有点曲线救国的味道。如果你的项目升级到 Vue 3,用
reactive和composition API来实现 MVP 会更自然,或者干脆用 Pinia 这种状态管理库,本质上也是在干类似的事情,只是封装得更完善。你原来的思路方向是对的,只是响应式这块没打通。Presenter 不应该是个纯函数集合,它得有能力管理状态并通知 View 更新。