从零开始构建MVC架构的前端项目实战经验分享
我的写法,亲测靠谱
先说说我在用MVC时的一些心得吧。我一般喜欢把控制器(Controller)弄得尽可能轻量,主要负责接收请求和返回响应,具体业务逻辑交给服务层去处理。这样做的好处是代码更容易测试,也方便后期维护。
举个例子,这是我常用的控制器写法:
class UserController {
constructor(userService) {
this.userService = userService;
}
async getUser(req, res) {
try {
const userId = req.params.id;
const user = await this.userService.fetchUser(userId);
return res.json(user);
} catch (error) {
console.error('获取用户信息失败:', error);
return res.status(500).json({ error: '服务器错误' });
}
}
}
这里我把用户相关的业务逻辑都抽到了userService里,控制器只负责调用和返回结果。这样做有几个好处:首先,单元测试更容易写了;其次,如果后面要改业务逻辑,不用动控制器的代码。
这几种错误写法,别再踩坑了
说真的,在用MVC的时候最容易犯的错误就是把所有逻辑都塞到控制器里。我就见过有人这么写的:
class BadController {
async handleRequest(req, res) {
// 数据库操作直接写在这里
const dbResult = await db.query(SELECT * FROM users WHERE id=${req.params.id});
// 业务逻辑也写在这里
if (dbResult.length > 0) {
const processedData = someComplexLogic(dbResult);
// 还有视图渲染
return res.render('template', { data: processedData });
}
return res.status(404).send('Not found');
}
}
这种写法简直就是灾难。我之前接手过一个项目,控制器里几千行代码,各种业务逻辑、数据库操作、格式转换全都搅在一起。改个需求得花好几天理清逻辑,太痛苦了。
实际项目中的坑
在真实项目里,我发现很多人对Model的理解也不太对。有次看到有人这么写Model:
class UserModel {
constructor(data) {
this.data = data;
}
saveToDatabase() {
// 直接在这里写数据库操作
return db.query('INSERT INTO users SET ?', this.data);
}
}
看着好像没啥问题,但实际上这种写法很危险。我建议把数据访问的逻辑单独抽出来,Model只负责定义数据结构和基本的验证规则:
class User {
constructor({id, name, email}) {
this.id = id;
this.name = name;
this.email = email;
}
validate() {
if (!this.name || !this.email) {
throw new Error('缺少必要字段');
}
}
}
class UserRepository {
async save(user) {
user.validate();
return db.query('INSERT INTO users SET ?', user);
}
}
`>
<p>这样分层更清晰,而且Repository可以针对不同的数据源做适配,比如换成MongoDB或者REST API都比较容易。</p>
<h2>关于View层的一些思考</h2>
<p>说到View层,我特别想提醒一下:千万别在模板里写太多逻辑。我遇到过一个项目,ejs模板里写满了if-else,还有复杂的循环嵌套:</p></code></pre>html
<% if (user.role === 'admin') { %>
<% for (let item of data) { %>
<% if (item.status === 'active') { %>
<div class="item"><%= item.name %></div>
<% } else { %>
<div class="disabled"><%= item.name %></div>
<% } %>
<% } %>
<% } else { %>
<p>无权限查看</p>
<% } %>
<pre class="pure-highlightjs line-numbers language-none"><code class="no-highlight language-none"><p>这种写法看起来就头疼。后来我改成这样:</p></code></pre>javascript
// 在控制器里预处理数据
const viewData = data.map(item => ({
...item,
className: item.status === 'active' ? 'item' : 'disabled'
}));
`>
<% if (user.role === 'admin') { %>
<% viewData.forEach(item => { %>
<div class="<%= item.className %>"><%= item.name %></div>
<% }) %>
<% } else { %>
<p>无权限查看</p>
<% } %>
这样模板就清爽多了,逻辑也更容易维护。
一些小技巧
- 我习惯在项目根目录放一个
config.js文件,专门存放各种配置项,比如API地址:https://jztheme.com/api,这样方便统一管理
- 用依赖注入的方式来组织各个模块的关系,这样测试起来会轻松很多
- 记得给每个模块写单元测试,特别是服务层的业务逻辑,这个真的能帮你省下不少调试时间
以上是我总结的最佳实践,有更好的方案欢迎评论区交流。说实话,MVC虽然老套,但确实是个经得起考验的架构模式,只要用得好,开发效率还是很可观的。
本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。

暂无评论