全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-16 10 分钟 ✍️ juanwangdev

MVC/MVVM架构

MVC和MVVM是前端架构的核心模式,理解它们的原理有助于更好地使用现代前端框架。

MVC架构模式

核心概念

MVC将应用分为三个核心组件:

  • Model:数据层,管理业务数据和逻辑
  • View:视图层,负责UI展示
  • Controller:控制器,处理用户交互,协调Model和View

MVC流程

JavaScript
用户操作 → Controller → Model更新 → View刷新

基础实现

JavaScript
// Model
class UserModel {
  constructor() {
    this.users = [];
    this.listeners = [];
  }

  addUser(user) {
    this.users.push(user);
    this.notify();
  }

  getUsers() {
    return this.users;
  }

  subscribe(listener) {
    this.listeners.push(listener);
  }

  notify() {
    this.listeners.forEach(listener => listener(this.users));
  }
}

// View
class UserView {
  constructor(container) {
    this.container = container;
  }

  render(users) {
    this.container.innerHTML = users.map(user =>
      `<div class="user">${user.name}</div>`
    ).join('');
  }

  bindAddUser(handler) {
    document.getElementById('addBtn').addEventListener('click', handler);
  }
}

// Controller
class UserController {
  constructor(model, view) {
    this.model = model;
    this.view = view;

    this.model.subscribe(users => this.view.render(users));
    this.view.bindAddUser(() => this.handleAddUser());
  }

  handleAddUser() {
    const name = document.getElementById('nameInput').value;
    this.model.addUser({ name });
  }
}

// 初始化
const model = new UserModel();
const view = new UserView(document.getElementById('userList'));
const controller = new UserController(model, view);

MVC变体

被动MVC

JavaScript
// View被动等待Controller更新
class UserView {
  render(users) {
    this.container.innerHTML = users.map(...);
  }
}

// Controller主动更新View
class UserController {
  handleAddUser() {
    this.model.addUser({ name });
    this.view.render(this.model.getUsers()); // Controller主动更新View
  }
}

主动MVC

JavaScript
// Model主动通知View更新(观察者模式)
class UserModel {
  notify() {
    this.listeners.forEach(listener => listener(this.users));
  }
}

class UserView {
  constructor(model) {
    this.model = model;
    model.subscribe(users => this.render(users)); // View订阅Model
  }
}

MVVM架构模式

核心概念

MVVM引入ViewModel层:

  • Model:数据层
  • View:视图层
  • ViewModel:视图模型,连接Model和View,实现数据绑定

MVVM流程

JavaScript
View ↔ ViewModel ↔ Model
(双向数据绑定)

数据绑定实现

JavaScript
// 简易MVVM实现
class ViewModel {
  constructor(data) {
    this.data = {};
    this.listeners = {};

    // 数据劫持
    Object.keys(data).forEach(key => {
      this.defineReactive(key, data[key]);
    });
  }

  defineReactive(key, value) {
    this.data[key] = value;
    this.listeners[key] = [];

    Object.defineProperty(this, key, {
      get() {
        return this.data[key];
      },
      set(newValue) {
        if (newValue === this.data[key]) return;
        this.data[key] = newValue;
        this.listeners[key].forEach(listener => listener(newValue));
      }
    });
  }

  watch(key, callback) {
    this.listeners[key].push(callback);
  }
}

// View绑定
class Binder {
  constructor(viewModel, view) {
    this.viewModel = viewModel;
    this.view = view;

    this.bindData();
    this.bindEvents();
  }

  bindData() {
    const inputs = this.view.querySelectorAll('[data-bind]');
    inputs.forEach(input => {
      const key = input.dataset.bind;

      // View → ViewModel
      input.addEventListener('input', () => {
        this.viewModel[key] = input.value;
      });

      // ViewModel → View
      this.viewModel.watch(key, (value) => {
        input.value = value;
      });
    });
  }

  bindEvents() {
    const buttons = this.view.querySelectorAll('[data-event]');
    buttons.forEach(button => {
      const [eventType, method] = button.dataset.event.split(':');
      button.addEventListener(eventType, () => {
        this.viewModel[method]();
      });
    });
  }
}

// 使用
const vm = new ViewModel({ name: '', age: '' });
const binder = new Binder(vm, document.getElementById('form'));

响应式实现(Proxy)

JavaScript
// 使用Proxy实现响应式
function reactive(data) {
  const callbacks = new Map();

  return new Proxy(data, {
    get(target, key) {
      return target[key];
    },

    set(target, key, value) {
      target[key] = value;

      if (callbacks.has(key)) {
        callbacks.get(key).forEach(cb => cb(value));
      }
      return true;
    }
  });
}

function watch(proxy, key, callback) {
  if (!proxy.callbacks) proxy.callbacks = new Map();
  proxy.callbacks.set(key, [callback]);
}

// 使用
const state = reactive({ count: 0, name: 'Alice' });
watch(state, 'count', (value) => {
  document.getElementById('count').textContent = value;
});

state.count = 10; // 自动更新UI

现代框架中的MVVM

Vue实现原理

JavaScript
// Vue响应式系统示意
function defineReactive(obj, key, value) {
  const dep = new Dep();

  Object.defineProperty(obj, key, {
    get() {
      if (Dep.target) {
        dep.addSub(Dep.target);
      }
      return value;
    },

    set(newValue) {
      if (newValue === value) return;
      value = newValue;
      dep.notify();
    }
  });
}

class Dep {
  constructor() {
    this.subs = [];
  }

  addSub(watcher) {
    this.subs.push(watcher);
  }

  notify() {
    this.subs.forEach(watcher => watcher.update());
  }
}

class Watcher {
  constructor(vm, key, callback) {
    this.vm = vm;
    this.key = key;
    this.callback = callback;

    Dep.target = this;
    this.value = vm[key]; // 触发getter,收集依赖
    Dep.target = null;
  }

  update() {
    const newValue = this.vm[this.key];
    this.callback(newValue);
  }
}

Vue组合式API

JavaScript
// Vue 3 Composition API
import { ref, reactive, computed, watch } from 'vue';

export default {
  setup() {
    // ref:基础类型响应式
    const count = ref(0);

    // reactive:对象响应式
    const state = reactive({
      name: 'Alice',
      age: 25
    });

    // computed:计算属性
    const doubleCount = computed(() => count.value * 2);

    // watch:侦听器
    watch(count, (newValue, oldValue) => {
      console.log(`count: ${oldValue}${newValue}`);
    });

    return {
      count,
      state,
      doubleCount
    };
  }
};

React的状态管理

text
// React单向数据流
function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  );
}

// 自定义Hook(类似ViewModel)
function useUserViewModel(initialUser) {
  const [user, setUser] = useState(initialUser);
  const [loading, setLoading] = useState(false);

  const updateUser = async (data) => {
    setLoading(true);
    const updated = await api.updateUser(data);
    setUser(updated);
    setLoading(false);
  };

  return { user, loading, updateUser };
}

MVC vs MVVM对比

特性MVCMVVM
数据流单向双向绑定
View更新Controller主动/被动自动响应
测试性较易ViewModel易测试
适用场景服务端渲染客户端渲染
代表框架BackboneVue、Angular

选择建议

text
简单页面/服务端渲染 → MVC
复杂交互/客户端渲染 → MVVM

MVVM的双向绑定简化了View更新逻辑,但也增加了调试难度。

架构实践示例

用户管理模块(MVVM)

text
class UserViewModel {
  constructor(api) {
    this.api = api;
    this.users = reactive([]);
    this.loading = reactive(false);
    this.error = reactive(null);
  }

  async fetchUsers() {
    this.loading = true;
    this.error = null;

    try {
      const users = await this.api.getUsers();
      this.users = users;
    } catch (err) {
      this.error = err.message;
    } finally {
      this.loading = false;
    }
  }

  async addUser(user) {
    try {
      const created = await this.api.createUser(user);
      this.users.push(created);
    } catch (err) {
      this.error = err.message;
    }
  }
}

// View绑定
class UserView {
  constructor(viewModel) {
    this.viewModel = viewModel;
    this.bind();
  }

  bind() {
    // 数据绑定
    watch(this.viewModel, 'users', users => this.renderUsers(users));
    watch(this.viewModel, 'loading', loading => this.toggleLoader(loading));
    watch(this.viewModel, 'error', error => this.showError(error));

    // 事件绑定
    document.getElementById('refreshBtn').addEventListener('click',
      () => this.viewModel.fetchUsers());
  }

  renderUsers(users) {
    const list = document.getElementById('userList');
    list.innerHTML = users.map(u => `<li>${u.name}</li>`).join('');
  }

  toggleLoader(loading) {
    document.getElementById('loader').style.display = loading ? 'block' : 'none';
  }
}

要点总结

  1. MVC三层:Model数据、View展示、Controller协调
  2. MVVM核心:ViewModel实现数据绑定,解耦View和Model
  3. 数据绑定:Object.defineProperty或Proxy实现响应式
  4. Vue实现:依赖收集 + 响应式劫持 + Watcher更新
  5. React差异:单向数据流,使用setState触发更新

存放路径:articles/JS/专家/设计模式与架构思想/MVC/MVVM架构.md

📝 发现内容有误?点击此处直接编辑

← 上一篇 输出编码与转义
下一篇 → 代理模式与装饰器模式
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库