案例挑战——MVVM框架理解和实践

简介: 案例挑战——MVVM框架理解和实践

MVVM框架理解和实践


一、背景介绍

最近正在做新版项目的MVVM架构的结合业务的具体落地,前后与领导进行了多次的交流和沟通,从业务的简单例子入手更改了五版代码。最终输出了一版比较完善的符合MVVM架构和业务需求的模板代码。通过这次的案例挑战,对MVVM架构有了相对于此前更为深层次的理解,通过博客总结的方式进行记录和明确自己的收获。


二、 什么是MVVM架构?

MVVM(Model-View-ViewModel)一种中架构模式,将应用程序的用户界面(视图)与后端逻辑(模型)进行解耦。它通过引入一个视图模型(ViewModel)来实现分离。


在MVVM架构模式中,**模型(Model)**代表应用程序的数据和业务逻辑(与后端服务器进行交互,从数据源中检索数据并进行处理和操作),**视图(View)**是用户界面的可视部分,负责展示数据和接收用户的输入。**视图模型(ViewModel)**为模型和视图之间的中间层,负责处理视图和模型之间的通信和交互也就是将模型数据转换成视图可用的形式,并处理视图的用户交互事件。


1.架构示意图

2f1376b250414e80a47e984f486a1d10.png

视图模型通过绑定机制将视图和模型连接起来,保持他们之间的同步,当模型的数据发生变化时,视图模型会通知视图进行更新。当用户在视图上进行操作的时候,视图模型会将这些操作传递给模型进行处理。


2.MVVM概念总结

模型:代表应用程序的数据和业务逻辑,通常与后端数据源交互

视图:负责展示用户界面,并与用户进行交互

视图模型:连接视图和模型的桥梁,负责将模型数据转换成视图可用的形式,并处理视图的用户交互事件。


3.实现VM的框架

我们可以看出来MVVM框架的核心是视图模型(ViewModel),连接视图和模型的桥梁,负责将模型数据转换成视图可用的形式,并处理视图的用户交互事件。


目前有很多框架可以用来实现MVVM架构中的ViewModel部分:

如 Vue.js、Angular、React、knockout.js


三、通过案例来理解MVVM框架

需求:现在在页面上有一个多选题,页面显示的数据有题目、内容、多个选项。

现在用户进行答题,选择选项后进行提交调用后端的答题接口。


主要的实现思路是,将前端界面上需要的数据正确的显示在页面中,当用户进行答题之后,拿到用户的答题信息,并转为后端需要的数据结构。


页面显示的数据源:

// 定义数据模型
        const questionData ={
                            questionnaireGrainId: 111,
                            title: '1.1.1.3 调查问卷:《Python语言的特点》,时间:0.5min',
                            content: '题目:下列选项中,不属于Python语言特点的是( )',
                            optionList: [
                                {
                                    optionId: 333,
                                    questionnaireGrainId: 111,
                                    optionContent: '苹果',
                                },
                                {
                                    optionId: 334,
                                    questionnaireGrainId: 111,
                                    optionContent: '橡胶',
                                },
                                {
                                    optionId: 335,
                                    questionnaireGrainId: 111,
                                    optionContent: '香蕉',
                                },
                                {
                                    optionId: 336,
                                    questionnaireGrainId: 111,
                                    optionContent: '梨',
                                }
                            ]
                        };

页面效果:

016d742928454a28b0cbf1049d9b573e.png

后端需要的数据结构示例:

{
  "questionnaireGrainId": 111,
  "questionnaireOptionParticipation": [
    {
      "optionId": "333"
    },
    {
      "optionId": "334"
    }
  ]
}

1.没有使用MVVM架构的程序

整体代码:

<!DOCTYPE html>
<html>
<head>
    <title>多选题示例</title>
</head>
<body>
    <!-- 绑定数据的容器 -->
        <div id="app">
        </div>
        <button type="button" onclick="submitAnswers()">提交</button>
    <script>
        // 定义数据模型
        const questionData ={
                            questionnaireGrainId: 111,
                            title: '1.1.1.3 调查问卷:《Python语言的特点》,时间:0.5min',
                            content: '题目:下列选项中,不属于Python语言特点的是( )',
                            optionList: [
                                {
                                    optionId: 333,
                                    questionnaireGrainId: 111,
                                    optionContent: '苹果',
                                },
                                {
                                    optionId: 334,
                                    questionnaireGrainId: 111,
                                    optionContent: '橡胶',
                                },
                                {
                                    optionId: 335,
                                    questionnaireGrainId: 111,
                                    optionContent: '香蕉',
                                },
                                {
                                    optionId: 336,
                                    questionnaireGrainId: 111,
                                    optionContent: '梨',
                                }
                            ]
                        };
        //后端需要的数据结构
        const questionnaireParticipation = {
          questionnaireGrainId: null,
          questionnaireOptionParticipation: [],
        };
            // 获取容器元素
            const appContainer = document.getElementById('app');
            // 创建标题元素并添加到容器中
            const titleElement = document.createElement('h1');
            titleElement.textContent = questionData.title;
            appContainer.appendChild(titleElement);
            // 创建内容元素并添加到容器中
            const contentElement = document.createElement('p');
            contentElement.textContent = questionData.content;
            appContainer.appendChild(contentElement);
            // 创建复选框元素并添加到容器中
            questionData.optionList.forEach(option => {
                const checkbox = document.createElement('input');
                checkbox.type = 'checkbox';
                checkbox.name = 'optionList';
                checkbox.value = option.optionId;
                const label = document.createElement('label');
                label.appendChild(checkbox);
                label.appendChild(document.createTextNode(option.optionContent));
                label.appendChild(document.createElement('br'));
                appContainer.appendChild(label);
            });
        //用户答题方法
        function submitAnswers() {
            // 获取所有被选中的选项
            const optionsData=[];
            const optionElems = document.querySelectorAll('input');
            // 将选项的值存入数组中
            optionElems .forEach(elem => {
                if (elem.checked) {
                const optionId = elem.value;
                optionsData.push({optionId});
                }
            });
            console.log(`用户选择的选项为:`,optionsData);
        // 遍历选项数据,赋值到后端需要的数据结构中
        for (let i = 0; i < optionsData.length; i++) {
        questionnaireParticipation.questionnaireGrainId=questionData.questionnaireGrainId;
        questionnaireParticipation.questionnaireOptionParticipation.push(optionsData[i])
        }
        console.log("questionnaireParticipation数据结构",questionnaireParticipation);
        // 将 questionnaireParticipation 数组转换为 JSON 字符串
        let questionnaireParticipationDataJson = JSON.stringify(questionnaireParticipation);
        // 在控制台中打印 JSON 字符串
        console.log(questionnaireParticipationDataJson);
    }
    </script>
</body>
</html>

打印出的数据结构示例:

{
  "questionnaireGrainId": 111,
  "questionnaireOptionParticipation": [
    {
      "optionId": "334"
    },
    {
      "optionId": "335"
    }
  ]
}

2.使用了MVVM架构的程序

这里通过采用VUE框架在实现VM。

<!DOCTYPE html>
<html>
    <head>
        <title>多选题示例</title>
            <!-- 引入 Vue.js -->
            <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
    </head>
    <body>
        <!-- 绑定 Vue.js 实例 -->
            <div id="app">
                <h2>{{ question.title }}</h2>
                <p>{{ question.content }}</p>
                <form>
                    <label v-for="option in question.optionList" :key="option.optionId"  >
                        <input type="checkbox" v-model="questionnaireParticipation.questionnaireOptionParticipation" :value="{
                            optionId:option.optionId
                        }">
                        {{ option.optionContent }}
                    </label><br>
                    <button type="button" @click="submitAnswers">提交</button>
                </form>
            </div>
    </body>
    <!-- 引入 Vue.js 实例脚本 -->
    <script src="questionnaire-articipation-app.js"></script>
</html>
// 定义数据模型
const questionData ={
                    questionnaireGrainId: 111,
                    title: '1.1.1.3 调查问卷:《Python语言的特点》,时间:0.5min',
                    content: '题目:下列选项中,不属于Python语言特点的是( )',
                    optionList: [
                        {
                            optionId: 333,
                            questionnaireGrainId: 111,
                            optionContent: '苹果',
                        },
                        {
                            optionId: 334,
                            questionnaireGrainId: 111,
                            optionContent: '橡胶',
                        },
                        {
                            optionId: 335,
                            questionnaireGrainId: 111,
                            optionContent: '香蕉',
                        },
                        {
                            optionId: 336,
                            questionnaireGrainId: 111,
                            optionContent: '梨',
                        }
                    ]
                };
        //第四版
        new Vue({
            el: '#app',
            data: {
                question:questionData,
                questionnaireParticipation: {
                  questionnaireGrainId:questionData.questionnaireGrainId,
                  questionnaireOptionParticipation:[],
                  }
            },
            methods: {
                submitAnswers: function() {
                    //调用后端接口..............
                    //打印数据结构
                    let actorDataJson = JSON.stringify(this.questionnaireParticipation);
                           // 在控制台中打印 JSON 字符串
                           console.log(actorDataJson);
                }
            }
        });

打印出的数据结构示例:

{
  "questionnaireGrainId": 111,
  "questionnaireOptionParticipation": [
    {
      "optionId": 333
    },
    {
      "optionId": 334
    }
  ]
}

补充:上面使用MVVM架构的程序,它的V是呈现的html代码,无业务逻辑(如:多选框、按钮、相应对象触发的事件)

VM:监听V、M处理V需要做的业务逻辑,决定将那个M数据渲染给那个V,以及选择那个M进行业务处理

M:js代码,前端数据载体,通过axios组件向后端发送http请求


3.对比

1.从上面两版代码最直观的感觉是,使用MVVM架构的程序的代码更为简洁,层次更为清晰。分为了三层,视图层、模型层、视图模型层(这里有vue提供)。


2.从上面的代码可以看出使用MVVM架构的程序在代码上根本就没有做数据结构转换的步骤(将用户答题的数据,将其转换为后端程序需要的数据结构),而是用户选择什么数据,通过VM直接就是我后端需要的数据结构。VM做了数据交互的部分,并使用{}符号定义对象。


3.使用MVVM架构的程序,将视图与模型之间进行了解耦,与没有实现MVVM架构的程序相比,那么我的V和我的M就能够实现高复用,相似的业务等等,都用这一套M。


四、总结

1.通过这一次的案例挑战,对于MVVM架构有了更进一步的理解,理论结合实践,并且需要和高人进行交流和请教高人。

2.目前只是对MVVM架构有了一些理解,后续还需要再项目实践中进行刻意练习和思考。目前是对于理解MVVM架构打下了前提。


目录
相关文章
|
2月前
|
XML 前端开发 JavaScript
前端技术的演变与实战应用
前端技术的演变与实战应用
|
2月前
|
人工智能 前端开发 测试技术
AI:探究下前端组件化设计的实现方法及其重要性(一)
AI:探究下前端组件化设计的实现方法及其重要性
|
2月前
|
人工智能 缓存 前端开发
AI:探究下前端组件化设计的实现方法及其重要性(二)
AI:探究下前端组件化设计的实现方法及其重要性
|
2月前
|
设计模式 前端开发 Android开发
Android应用开发中的MVP架构模式解析
【5月更文挑战第25天】本文深入探讨了在Android应用开发中广泛采用的一种设计模式——Model-View-Presenter (MVP)。文章首先概述了MVP架构的基本概念和组件,接着分析了它与传统MVC模式的区别,并详细阐述了如何在实际开发中实现MVP架构。最后,通过一个具体案例,展示了MVP架构如何提高代码的可维护性和可测试性,以及它给开发者带来的其他潜在好处。
|
测试技术 数据库 安全
带你读《C++代码整洁之道:C++17 可持续软件开发模式实践》之二:构建安全体系
如果想用C++语言编写出易维护的、扩展性良好的以及生命力强的软件,那么,对于所有的软件开发人员、软件设计人员、对现代C++代码感兴趣或想降低开发成本的项目领导者来说,本书都是必需品。如果你想自学编写整洁的C++代码,那么本书也是你需要的。本书旨在通过一些示例帮助各个技术层次的开发人员编写出易懂的、灵活的、可维护的和高效的C++代码。即使你是一名资深的开发工程师,在本书中也可以找到有价值的知识点。
|
2月前
|
Cloud Native 算法 程序员
代码与禅意:编程中的哲学思考构建未来:云原生架构在现代企业中的应用与挑战
【5月更文挑战第30天】 在数字世界的繁花似锦之下,编程不仅仅是一种技能,更是一场关于逻辑、美学和哲学的深刻对话。本文将探讨编程过程中所体现出的哲学理念,从禅宗的角度出发,揭示代码背后蕴含的深层次意义。我们将一同走进程序员的内心世界,体会在面对复杂问题时,如何通过冥想般的编码实践,达到问题解决的顿悟。
|
17天前
|
设计模式 人工智能 自然语言处理
【设计模式】MVVM模式在AI大模型领域的创新应用
【设计模式】MVVM模式在AI大模型领域的创新应用
26 0
|
2月前
|
存储 前端开发 Java
Android应用开发中的MVP架构模式实践
【5月更文挑战第5天】随着移动应用开发的复杂性增加,传统的MVC(Model-View-Controller)架构在应对大型项目时显得笨重且不灵活。本文将探讨一种更适应现代Android应用开发的架构模式——MVP(Model-View-Presenter),并展示如何在Android项目中实现该模式以提升代码的可维护性和可测试性。通过对比分析MVP与传统MVC的差异,以及提供一个实际案例,读者将能深入了解MVP的优势和实施步骤。
|
2月前
|
前端开发 测试技术 数据处理
安卓开发中的MVP架构模式深度解析
【4月更文挑战第30天】在移动应用开发领域,模型-视图-呈现器(Model-View-Presenter, MVP)是一种广泛采用的架构模式。它旨在通过解耦组件间的直接交互来提高代码的可维护性和可测试性。本文将深入探讨MVP在安卓开发中的应用,揭示其如何促进代码的模块化,提升用户界面的响应性,并简化单元测试过程。我们将从理论概念出发,逐步过渡到实践案例,为读者提供一套行之有效的MVP实施策略。
|
2月前
|
大数据 图形学 云计算
EDA设计:技术深度解析与实战代码应用
EDA设计:技术深度解析与实战代码应用