MVC 架構和框架

MVC 架構讓複雜應用的開發過程變得更易於管理,它允許多個開發者協同開發。

第一次瞭解 MVC 模式時,我被這些術語嚇到了,當我實際運用這些概念時更是如此。

回過頭去,理解了 MVC 的含義以及作用,就能更輕鬆地將它運用於 web 應用的開發。

什麼是 MVC

MVC,即 model-view-controller,其中每個組件的含義如下:

MVC 的概念最早由 Trygve Reenskaug 提出,他提出將其作爲一種開發桌面應用 GUI 的方式。

如今 MVC 被用於現代 web 應用開發,因爲它增強了應用的靈活性、可維護性和可擴展性。

爲什麼要用 MVC?

五個字:關注點分離(separation of concerns,縮寫爲 SoC)

MVC 模式有助於將前端和後端代碼拆分爲獨立的組件,這樣更便於管理,而且能夠更方便地改動其中的某一部分而不會互相影響。

不過說起來容易做起來難,尤其是多個開發者同時更新、修改或調試一個成熟應用時。

如何使用 MVC

爲了更好地說明 MVC 模式,我引入了一個 web 應用,它展示了這些概念是如何工作的。

我的 Car Clicker 應用是著名的 Cat Clicker 應用的變體。

我的應用主要有以下區別:

  1. 沒有貓咪,只有性能車的圖片(對不住了,愛貓人士!)

  2. 列出了多種車型

  3. 有多個點擊計數器

  4. 只展示選中的車

讓我們深入瞭解一下構成 MVC 架構模式的三個組件。

模型(數據)

模型的任務是管理數據。不論數據是來自數據庫、API 還是 JSON 對象,模型都要負責管理它們。

在 Car Clicker 應用中,模型對象包含一個由 car 對象組成的數組,其中含有這個應用所需的所有信息(數據)。

它還通過一個初始值爲 null 的變量 currentCar 控制當前展示哪個汽車。

const model = {
    currentCar: null,
    cars: [
        {
            clickCount: 0,
            name: 'Coupe Maserati',
            imgSrc: 'img/black-convertible-coupe.jpg',
        },
        {
            clickCount: 0,
            name: 'Camaro SS 1LE',
            imgSrc: 'img/chevrolet-camaro.jpg',
        },
        {
            clickCount: 0,
            name: 'Dodger Charger 1970',
            imgSrc: 'img/dodge-charger.jpg',
        },
        {
            clickCount: 0,
            name: 'Ford Mustang 1966',
            imgSrc: 'img/ford-mustang.jpg',
        },
        {
            clickCount: 0,
            name: '190 SL Roadster 1962',
            imgSrc: 'img/mercedes-benz.jpg',
        },
    ],
};

視圖(UI)

視圖決定了用戶看到的內容以及交互方式。

Car Clicker 應用有兩個視圖:carListViewCarView

每個視圖都有兩個關鍵函數,定義其如何初始化及如何渲染。

這些函數決定了用戶將會看到的內容以及交互方式。

carListView

const carListView = {
    init() {
        // 保存 DOM 元素,方便後續訪問
        this.carListElem = document.getElementById('car-list');

        // 渲染視圖(使用正確的數據更新 DOM 元素)
        this.render();
    },

    render() {
        let car;
        let elem;
        let i;
        // 從控制器中獲取待展示的汽車
        const cars = controller.getCars();

        // 確保渲染前列表是空的
        this.carListElem.innerHTML = '';

        // 遍歷 cars 數組
        for(let i = 0; i < cars.length; i++) {
            // 當前遍歷到的車
            car = cars[i];

            // 創建一個汽車列表項(<li>)並設置其文本
            elem = document.createElement('li');
            elem.className = 'list-group-item d-flex justify-content-between lh-condensed';
            elem.style.cursor = 'pointer';
            elem.textContent = car.name;
            elem.addEventListener(
                'click',
                (function(carCopy) {
                    return function() {
                        controller.setCurrentCar(carCopy);
                        carView.render();
                    };
                })(car)
            );
            // 最後將其加入列表
            this.carListElem.appendChild(elem);
        }
    },
};

CarView

const carView = {
    init() {
        // 保存 DOM 元素指針,方便後續訪問
        this.carElem = document.getElementById('car');
        this.carNameElem = document.getElementById('car-name');
        this.carImageElem = document.getElementById('car-img');
        this.countElem = document.getElementById('car-count');
        this.elCount = document.getElementById('elCount');


        // 點擊時增加當前汽車的計數
        this.carImageElem.addEventListener('click', this.handleClick);

        // 渲染視圖(使用正確的數據更新 DOM 元素)
        this.render();
    },

    handleClick() {
     return controller.incrementCounter();
    },

    render() {
        // 使用當前汽車的數據更新 DOM 元素
        const currentCar = controller.getCurrentCar();
        this.countElem.textContent = currentCar.clickCount;
        this.carNameElem.textContent = currentCar.name;
        this.carImageElem.src = currentCar.imgSrc;
        this.carImageElem.style.cursor = 'pointer';
    },
};

控制器(大腦)

控制器負責獲取數據、修改數據,併爲用戶提供數據。本質上,控制器就是視圖和模型之間的鏈接。

通過 getter 和 setter 函數,控制器從模型拉取數據並初始化視圖。

如果視圖要更新後臺數據,它會通過 setter 函數來修改數據。

const controller = {
    init() {
        // 將當前展示的車設爲列表中的第一輛車
        model.currentCar = model.cars[0];

        // 初始化視圖
        carListView.init();
        carView.init();
    },

    getCurrentCar() {
     return model.currentCar;
    },

    getCars() {
     return model.cars;
    },

    // 把“當前選中汽車”設爲傳入的對象
    setCurrentCar(car) {
     model.currentCar = car;
    },

    // 增加當前選中汽車的計數
    incrementCounter() {
        model.currentCar.clickCount++;
        carView.render();
    },
};

// Let's goooo!
controller.init();

MVC 框架

JavaScript 越來越受歡迎,近年來還接管了後端。越來越多成熟的 JavaScript 應用選擇了 MVC 架構模式。

框架來來去去,但是 MVC 架構模式的概念是不變的。

運用了這些概念的早期框架包括:KnockoutJSDjangoRuby on Rails

總結

MVC 模式最吸引人的概念是關注點分離。

現代 web 應用非常複雜,有時做一些修改會令人很頭疼。

將前端和後端作爲獨立的小組件來管理,可以使應用更靈活、更易於維護和擴展。

**如果你想了解這個 Car Clicker 應用,可以查看__源碼__或體驗__在線版本_。_**

🌟感謝你的閱讀!🌟

原文鏈接:https://www.freecodecamp.org/news/the-model-view-controller-pattern-mvc-architecture-and-frameworks-explained/

作者:Rafael D. Hernandez

譯者:Humilitas

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/bfyJhP_zJ5CRI9XTCkFJgQ