前端实践:前端框架设计模式详解 | 青训营

128 阅读5分钟

一、前端设计框架中的设计模式对比及优缺点归纳

  1. MVC(Model-View-Controller)模式
  • 概念:MVC是一种软件架构模式,将应用程序分成三个主要部分:Model(模型)、View(视图)和Controller(控制器)。模型负责管理数据和业务逻辑,视图负责呈现数据,控制器负责处理用户输入和调度应用逻辑。
  • 优点:分离了数据、显示和控制逻辑,使代码更具组织性,易于维护和扩展。
  • 缺点:在大型应用中,模式可能会变得复杂,增加了代码的复杂性。
  1. MVVM(Model-View-ViewModel)模式
  • 概念:MVVM是一种在MVC模式基础上演化的模式,它将应用程序分为三个部分:Model、View和ViewModel。ViewModel是连接Model和View的中介,负责处理数据绑定和逻辑。
  • 优点:将视图与数据绑定,当数据改变时,视图自动更新,减少了手动DOM操作。
  • 缺点:复杂的数据绑定可能会导致性能问题,理解和调试可能相对复杂。
  1. 单向数据流(One-Way Data Flow)模式
  • 概念:单向数据流是一种数据管理模式,数据只能从一个方向流动,通常从父组件流向子组件。子组件通过触发事件来通知父组件进行状态的更改。
  • 优点:数据的流动方向清晰,易于追踪状态变化,降低了出现难以调试的问题的可能性。
  • 缺点:在某些情况下可能需要编写更多的代码来管理数据流。
  1. 依赖注入(Dependency Injection)模式
  • 概念:依赖注入是一种设计模式,它通过将依赖关系从组件内部移动到外部,将依赖项“注入”到组件中,降低了组件之间的耦合度。
  • 优点:降低了组件之间的耦合,易于测试和维护,使代码更加灵活和可扩展。
  • 缺点:可能增加代码的复杂性,需要更多的配置和管理。
  1. 观察者(Observer)模式
  • 概念:观察者模式定义了一种对象之间的一对多依赖关系,当一个对象(主题)的状态发生变化时,所有依赖于它的对象(观察者)会自动得到通知并更新。
  • 优点:实现了松散耦合,当一个对象改变状态时,所有依赖于它的对象都会得到通知。
  • 缺点:容易造成多级触发,导致性能问题。

二、使用案例

2.1 MVC(Model-View-Controller)模式

Backbone.js是一个MVC框架的代表。它将数据模型、视图和控制器分离,使开发者可以更好地管理代码。使用Backbone.js构建一个简单的任务列表应用程序。

  • 定义任务类型(Model)
var Task = Backbone.Model.extend({
  defaults: {
    title: "",
    completed: false
  }
});
  • 创建任务集合(Collection)
var TasksCollection = Backbone.Collection.extend({
  model: Task
});
  • 创建任务视图(View)
var TaskView = Backbone.View.extend({
  tagName: "li",
  template: _.template($("#task-template").html()),

  initialize: function() {
    this.listenTo(this.model, "change", this.render);
  },

  render: function() {
    this.$el.html(this.template(this.model.toJSON()));
    return this;
  }
});
  • 创建主应用视图(View)
var AppView = Backbone.View.extend({
  initialize: function() {
    this.tasksListView = new TasksListView();
  }
});

$(function() {
  new AppView();
});
  • HTML模板和页面结构
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Backbone.js Tasks App</title>
</head>
<body>
  <h1>Task List</h1>
  <form id="add-task-form">
    <input type="text" id="task-title" placeholder="Enter task title">
    <button type="submit">Add Task</button>
  </form>
  <div id="tasks-list">
    <ul></ul>
  </div>

  <script type="text/template" id="task-template">
    <input type="checkbox" <% if (completed) { %>checked<% } %>>
    <%- title %>
  </script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.13.1/underscore-min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.4.0/backbone-min.js"></script>
  <script src="app.js"></script>
</body>
</html>

2.2 MVVM(Model-View-ViewModel)模式

Vue.js是一个流行的MVVM框架。它通过数据绑定实现了视图与数据的同步更新,使开发更高效。使用Vue.js创建一个动态展示文章列表的应用。

  • 首先,在HTML文件中设置基本的结构,包括Vue.js库、文章列表容器和模板:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Vue.js Article List App</title>
</head>
<body>
  <div id="app">
    <h1>Article List</h1>
    <ul>
      <li v-for="article in articles" :key="article.id">{{ article.title }}</li>
    </ul>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script>
  <script src="app.js"></script>
</body>
</html>
  • app.js中,创建一个Vue实例并定义初始数据:
const app = new Vue({
  el: '#app',
  data: {
    articles: [
      { id: 1, title: 'Introduction to Vue.js' },
      { id: 2, title: 'Getting Started with Vue Components' },
      { id: 3, title: 'Vue Router: Building Single Page Applications' }
      // ... 更多文章
    ]
  }
});
注:使用了Vue的指令`v-for`来循环渲染文章列表中的每一篇文章 
  • 将上述代码保存为app.js,并在浏览器中打开HTML文件,即可

2.3 单向数据流(One-Way Data Flow)模式

React采用了单向数据流的概念。组件的数据从父组件向子组件传递,状态变化通过事件触发并通过状态管理库(如Redux)进行管理。使用React构建一个简单的待办事项列表应用。

  • 设置环境(初始化react)
npx create-react-app todo-app
cd todo-app
  • 创建组件(在src目录中,打开App.js文件并替换其内容)
import React, { useState } from 'react';
import './App.css';

function App() {
  const [todos, setTodos] = useState([]);
  const [newTodo, setNewTodo] = useState('');

  const addTodo = () => {
    if (newTodo.trim() !== '') {
      setTodos([...todos, { id: Date.now(), text: newTodo }]);
      setNewTodo('');
    }
  };

  const removeTodo = (id) => {
    setTodos(todos.filter(todo => todo.id !== id));
  };

  return (
    <div className="App">
      <h1>Todo List</h1>
      <input
        type="text"
        value={newTodo}
        onChange={e => setNewTodo(e.target.value)}
        placeholder="Enter a new todo"
      />
      <button onClick={addTodo}>Add</button>
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            {todo.text}
            <button onClick={() => removeTodo(todo.id)}>Remove</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;
  • 运行应用(在根目录启动)
npm start

2.4 依赖注入(Dependency Injection)模式

Angular框架使用依赖注入来管理组件之间的依赖关系。通过将依赖项注入到组件中,使得组件更具可测试性和可复用性。使用Angular创建一个用户管理系统。

  • 创建项目和组件
ng new user-management
cd user-management
ng generate component user-list
ng generate component user-details
  • 定义模型(在src/app目录中,创建一个user.model.ts文件来定义用户模型)
export interface User {
  id: number;
  name: string;
  email: string;
}
  • 编辑组件
    • src/app/user-list目录中,编辑user-list.component.ts文件
    import { Component, OnInit } from '@angular/core';
    import { User } from '../user.model';
    
    @Component({
      selector: 'app-user-list',
      templateUrl: './user-list.component.html',
      styleUrls: ['./user-list.component.css']
    })
    export class UserListComponent implements OnInit {
      users: User[] = [
        { id: 1, name: 'John Doe', email: 'john@example.com' },
        { id: 2, name: 'Jane Smith', email: 'jane@example.com' }
      ];
    
      constructor() { }
    
      ngOnInit(): void {
      }
    }
    
    • src/app/user-list目录中,编辑user-list.component.html文件
    <h2>User List</h2>
    <ul>
      <li *ngFor="let user of users">
        {{ user.name }} - {{ user.email }}
      </li>
    </ul>
    
  • 编辑主应用组件(在src/app目录中,编辑app.component.html文件)
<h1>User Management System</h1>
<app-user-list></app-user-list>
  • 运行应用
ng serve

2.5 观察者(Observer)模式

Knockout.js使用观察者模式来实现数据绑定。当数据变化时,绑定的视图会自动更新。使用Knockout.js构建一个实时更新的股票价格显示应用。

  • 创建一个HTML文件,包含用于展示股票价格的元素
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Knockout.js Stock Price App</title>
</head>
<body>
  <h1>Stock Price App</h1>
  <ul data-bind="foreach: stocks">
    <li>
      <span data-bind="text: name"></span>: <span data-bind="text: price"></span>
    </li>
  </ul>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-min.js"></script>
  <script src="app.js"></script>
</body>
</html>
  • 创建Knockout.js视图模型(在app.js中,创建Knockout.js视图模型来管理股票数据和实时更新)
function Stock(name, initialPrice) {
  this.name = name;
  this.price = ko.observable(initialPrice);
}

function StockViewModel() {
  var self = this;

  self.stocks = ko.observableArray([
    new Stock('AAPL', 150),
    new Stock('GOOGL', 2700),
    new Stock('AMZN', 3300)
  ]);

  // Simulate real-time price updates
  setInterval(function() {
    self.stocks().forEach(function(stock) {
      stock.price(stock.price() + (Math.random() - 0.5) * 10);
    });
  }, 2000);
}

var viewModel = new StockViewModel();
ko.applyBindings(viewModel);
  • 运行应用:将上述代码保存为app.js,然后在浏览器中打开HTML文件,你将看到一个简单的股票价格显示应用,股票价格会每隔2秒钟随机变化。