热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

怎樣完成一個MV*形式(MVC/MVP/MVVM)

如果讓你不依託任何前端框架(ReactVueAngular等等),純真用Javascript編寫一個網站運用,你還知道怎樣開闢嗎?舉個例子,產物司理讓你完成一個網頁,上面有一張貓咪

如果讓你不依託任何前端框架(React/Vue/Angular等等),純真用Javascript編寫一個網站運用,你還知道怎樣開闢嗎?

舉個例子,產物司理讓你完成一個網頁,上面有一張貓咪的圖片,貓咪的下面顯現點贊的次數。每次點擊貓咪的圖片,點贊的数字加一。

這個對人人來講應當都很簡樸。

這時刻產物司理最先加需求了,網頁上展現五張貓咪圖片,離別有本身的點贊次數,點擊貓咪圖片,相對應的點贊次數加一。這時刻你想怎樣改寫本身的順序呢?你的順序如今看起來是不是邏輯清楚,構造清楚,可拓展性強呢?

本日我就要帶人人用MV形式來構造代碼,編寫出高質量幽美的前端項目。起首我們要也許搞清楚一些什麼MV形式。

什麼MV*形式

MV*是MVC/MVP/MVVM等的一個統稱,它們各有不同,但本質上實際上是一個東西。MVP和MVVM是MVC的變體。所以我們本日不議論它們的區分,只關注中心的東西。

M代表的是Model,用於封裝與運用順序的營業邏輯相干的數據以及對數據的處置懲罰要領。Model有對數據直接接見的權利,比方對數據庫的接見。Model 不體貼它會被怎樣顯現或是怎樣被操縱。

V代表的是View,用於將數據有目標的顯現出來,在 View 中平常沒有順序上的邏輯。

末了的*,不管是Controller照樣Presenter,照樣ViewModel,本質上做的事變就是銜接M和V,搭建M和V溝通的橋樑。讓M和V不直接溝通,到達職責星散的結果。

我們能夠看維基百科上一個極簡的MVC完成:

/** 模仿 Model, View, Controller */
var M = {}, V = {}, C = {};
/** Model 擔任寄存材料 */
M.data = "hello world";
/** View 擔任將材料顯現到屏幕上 */
V.render = (m) => { alert(m.data); }
/** Controller 作為一個 M 和 V 的橋樑 */
C.handleOnload= () => { V.render(M); }
/** 在網頁讀取的時刻挪用 Controller */
window.Onload= C.handleOnload;

我們本日要完成的MV*就要滿足這幾個前提:

  1. Model保留我們的數據
  2. View擔任襯着節點,能夠有多個View
  3. *(我們給它取個名字叫Bridge)為View供應讀取和修正Model的要領

產物司理的需求

最終版:網頁左邊展現一個可挑選的貓咪名字列表,右邊展現當前選中的貓咪概況,包含貓咪稱號,貓咪圖片,該貓咪被點贊數目和一個點贊按鈕。點擊點贊按鈕,當前貓咪的點贊數目加1。結果圖以下,我們只體貼功用完成,所以款式丑我們先忍一下。

《怎樣完成一個MV*形式(MVC/MVP/MVVM)》

HTML && CSS





    placekitten


    👏


    構造很清楚,主要有一個id是cat-list的貓咪列表和一個id是cat-container的貓咪概況,貓咪概況包含三部份,貓咪名字,貓咪圖片和點贊區。增加一點簡樸的款式。

    #main {
    display: flex;
    }
    #cat-list {
    flex: 0 0 100px;
    }
    #cat-list li {
    cursor: pointer;
    }
    #cat-container {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    }
    #cat-img {
    width: 300px;
    height: 300px;
    }
    #likes-btn {
    cursor: pointer;
    }

    Model

    let model = {
    currentCat: null,
    cats: [
    {
    title: '我是一號喵喵',
    imageSrc: 'https://placekitten.com/300/300',
    likesCount: 0
    },
    {
    title: '我是二號喵喵',
    imageSrc: 'https://placekitten.com/301/301',
    likesCount: 0
    },
    {
    title: '我是三號喵喵',
    imageSrc: 'https://placekitten.com/302/302',
    likesCount: 0
    },
    {
    title: '我是四號喵喵',
    imageSrc: 'https://placekitten.com/303/303',
    likesCount: 0
    }
    ]
    };

    我們的數據包含兩部份,currentCat示意當前展現的貓咪概況對象, cats示意貓咪列表。能夠看出我們如今的Model就是純真的數據展現,沒有任何與展現相干的邏輯,將來拓展起來異常輕易。

    Bridge

    方才說了Bridge要擔任為View供應一切對Model數據的讀取和修正的要領。所以我們能夠思索下,有哪些要領須要供應。

    1. 起首要供應一個Init的要領,實行初次襯着view的事情
    2. 獵取當前挑選的貓咪概況
    3. 才列表挑選要閱讀的貓咪
    4. 獵取貓咪列表
    5. 為當前挑選的貓咪點贊

    let brain = {
    init: () => {
    model.currentCat = model.cats[0]; //初始化 catListView.init(); //這兩個View稍後供應
    catView.init();
    },
    getCurrentCat: () => model.currentCat,
    setCurrentCat: (cat) => {
    model.currentCat = cat;
    catView.render(); // 手動觸發View從新襯着,這是將來我們的主要優化點
    },
    getCats: () => model.cats,
    incrementLikes: () => {
    model.currentCat.likesCount++;
    catView.render(); // 手動觸發View從新襯着,這是將來我們的主要優化點
    }
    };

    View

    我們有兩個View,一個是貓咪列表catListView, 另一個是貓咪概況catView。

    let catView = {
    init: function () {
    this.catTitle = document.getElementById('cat-title');
    this.catImg = document.getElementById('cat-img');
    this.likesCount = document.getElementById('likes-count');
    this.likesBtn = document.getElementById('likes-btn'); this.likesBtn.addEventListener('click', () => {
    brain.incrementLikes();
    }) this.render()
    },
    render: function () {
    let currentCat = brain.getCurrentCat();
    this.catTitle.textCOntent= currentCat.title;
    this.catImg.src = currentCat.imageSrc;
    this.likesCount.textCOntent= currentCat.likesCount;
    }
    }

    注意到,我們把init和render拆成兩個要領。

    init要領起首把相干的DOM節點先保留下來,防止後續每次還得從新尋覓DOM節點;然後為點贊按鈕綁定點擊事宜,點擊時挪用brain供應的incrementLikes要領修正Model;末了實行render完成初次襯着。

    而render函數儘管襯着,每次挪用都邑直接修正DOM節點,更新襯着。

    let catListView = {
    init: function () {
    this.catListElem = document.getElementById('cat-list');
    this.render();
    },
    render: function () {
    let cats = brain.getCats(); cats.forEach(cat => {
    let catElem = document.createElement('li');
    catElem.textCOntent= cat.title;
    catElem.addEventListener('click', () => {
    brain.setCurrentCat(cat);
    })
    this.catListElem.appendChild(catElem)
    })
    }
    }

    catListView構造與上面相似。

    設置完model, brain, catlistview, catview四個對象后,我們在末了挪用brain.init()就完成了一切事情。

    末了

    本日我們就完成了一個MV形式,它基本上歸納綜合了MV形式的中心。然則遺留了一個很主要的題目:每當我們數據修正的時刻,我們都手動挪用了一下view的render函數來從新襯着頁面,如許顯然是不智慧的。下期我們細緻研究一下MVVM的代表Backbone, knockout等等以及Vue是怎樣完成他們的MV*。


    推荐阅读
    • 本文探讨了在UIScrollView上嵌入Webview时遇到的一个常见问题:点击图片放大并返回后,Webview无法立即滑动。我们将分析问题原因,并提供有效的解决方案。 ... [详细]
    • php三角形面积,335宝石大全
      php三角形面积,335宝石大全 ... [详细]
    • android开发分享荐                                                         Android思维导图布局:效果展示及使用方法
      思维导图布局的前身是树形布局,对树形布局基本使用还不太了解的朋友可以先看看我写的树形布局系列教程,了解了树形布局的使用方法后再来阅读本文章。先睹为快来看看效果吧,横向效果如下:纵向 ... [详细]
    • 前言:由于Android系统本身决定了其自身的单线程模型结构。在日常的开发过程中,我们又不能把所有的工作都交给主线程去处理(会造成UI卡顿现象)。因此,适当的创建子线程去处理一些耗 ... [详细]
    • 编译原理中的语法分析方法探讨
      本文探讨了在编译原理课程中遇到的复杂文法问题,特别是当使用SLR(1)文法时遇到的多重规约与移进冲突。文章讨论了可能的解决策略,包括递归下降解析、运算符优先级解析等,并提供了相关示例。 ... [详细]
    • Flutter 核心技术与混合开发模式深入解析
      本文深入探讨了 Flutter 的核心技术,特别是其混合开发模式,包括统一管理模式和三端分离模式,以及混合栈原理。通过对比不同模式的优缺点,帮助开发者选择最适合项目的混合开发策略。 ... [详细]
    • 本文详细介绍了二叉堆的概念及其在Java中的实现方法。二叉堆是一种特殊的完全二叉树,具有堆性质,常用于实现优先队列。 ... [详细]
    • 使用C#构建动态图形界面时钟
      本篇文章将详细介绍如何利用C#语言开发一个具有动态显示功能的图形界面时钟。文章中不仅提供了详细的代码示例,还对可能出现的问题进行了深入分析,并给出了解决方案。 ... [详细]
    • 本文探讨了在使用JavaMail发送电子邮件时,抄送功能未能正常工作的问题,并提供了详细的代码示例和解决方法。 ... [详细]
    • Android开发:巧妙运用ViewStub写出类似Tab选项卡
      nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
    • Spring Boot使用AJAX从数据库读取数据异步刷新前端表格
        近期项目需要是实现一个通过筛选选取所需数据刷新表格的功能,因为表格只占页面的一小部分,不希望整个也页面都随之刷新,所以首先想到了使用AJAX来实现。  以下介绍解决方法(请忽视 ... [详细]
    • 本文详细介绍了Android系统的四层架构,包括应用程序层、应用框架层、库与Android运行时层以及Linux内核层,并提供了如何关闭Android系统的步骤。 ... [详细]
    • JUC并发编程——线程的基本方法使用
      目录一、线程名称设置和获取二、线程的sleep()三、线程的interrupt四、join()五、yield()六、wait(),notify(),notifyAll( ... [详细]
    • 在Java开发中,保护代码安全是一个重要的课题。由于Java字节码容易被反编译,因此使用代码混淆工具如ProGuard变得尤为重要。本文将详细介绍如何使用ProGuard进行代码混淆,以及其基本原理和常见问题。 ... [详细]
    • 本文探讨了如何在游戏启动画面中移除广告,特别是在游戏数据加载期间(大约5-6秒)广告会短暂显示的问题。通过调整XML布局和代码逻辑,可以实现广告的延迟加载或完全移除。 ... [详细]
    author-avatar
    PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
    Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有