案例挑战——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架构打下了前提。


目录
相关文章
|
7月前
|
XML 前端开发 JavaScript
前端技术的演变与实战应用
前端技术的演变与实战应用
|
测试技术 数据库 安全
带你读《C++代码整洁之道:C++17 可持续软件开发模式实践》之二:构建安全体系
如果想用C++语言编写出易维护的、扩展性良好的以及生命力强的软件,那么,对于所有的软件开发人员、软件设计人员、对现代C++代码感兴趣或想降低开发成本的项目领导者来说,本书都是必需品。如果你想自学编写整洁的C++代码,那么本书也是你需要的。本书旨在通过一些示例帮助各个技术层次的开发人员编写出易懂的、灵活的、可维护的和高效的C++代码。即使你是一名资深的开发工程师,在本书中也可以找到有价值的知识点。
|
2月前
|
存储 前端开发 JavaScript
前端技术深度探索:从基础到现代框架的实践之旅
前端技术深度探索:从基础到现代框架的实践之旅
45 3
|
2月前
|
设计模式 前端开发 JavaScript
深入探索研究MVVM架构设计
【10月更文挑战第7天】
35 0
|
4月前
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
113 0
|
6月前
|
设计模式 人工智能 自然语言处理
【设计模式】MVVM模式在AI大模型领域的创新应用
【设计模式】MVVM模式在AI大模型领域的创新应用
82 0
|
7月前
|
前端开发 测试技术 数据处理
安卓开发中的MVP架构模式深度解析
【4月更文挑战第30天】在移动应用开发领域,模型-视图-呈现器(Model-View-Presenter, MVP)是一种广泛采用的架构模式。它旨在通过解耦组件间的直接交互来提高代码的可维护性和可测试性。本文将深入探讨MVP在安卓开发中的应用,揭示其如何促进代码的模块化,提升用户界面的响应性,并简化单元测试过程。我们将从理论概念出发,逐步过渡到实践案例,为读者提供一套行之有效的MVP实施策略。
|
架构师 测试技术 API
深入浅出聊一聊自动化架构!
深入浅出聊一聊自动化架构!
179 1
|
7月前
|
前端开发 数据可视化 搜索推荐
数据驱动的前端设计与开发实践
本文将介绍如何在前端设计与开发中充分利用数据驱动的方法,通过数据分析、用户行为追踪和可视化等手段,指导前端界面设计和功能开发,提高用户体验和产品质量。
|
7月前
|
人工智能 前端开发 JavaScript
【利用AI让知识体系化】前端开发学习&了解业务架构(一)
【利用AI让知识体系化】前端开发学习&了解业务架构