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


目录
相关文章
|
1月前
|
开发工具 Android开发 UED
移动应用开发之旅:从概念到实现
本文将带领读者踏上一段探索移动应用开发的旅程,从最初的构想到最终的实现。我们将深入探讨移动应用的设计原则、开发工具的选择、操作系统的差异性以及如何优化用户体验。通过实际案例分析,我们将揭示如何将一个简单想法转化为数百万用户的日常伴侣。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和实用的技巧。
|
3月前
|
开发框架 Android开发 Swift
移动应用开发之旅:从概念到上线
【9月更文挑战第35天】在这篇文章中,我们将一起踏上一段激动人心的旅程,探索移动应用开发的奥秘。我们将从最初的构想出发,逐步深入到移动操作系统的核心,了解如何将这些想法转化为现实中的应用。文章不仅会涵盖开发流程的各个阶段,还将通过实际代码示例,展示如何在Android和iOS这两大主流平台上实现功能。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供宝贵的知识和技能,帮助你在移动应用领域取得成功。
|
2月前
|
Java 测试技术 Android开发
探索移动应用开发之旅:从概念到实现
【10月更文挑战第43天】本文将引导读者通过一个充满启发性的旅程,探讨移动应用开发背后的哲学和实践。我们将从一个简单的想法出发,逐步揭示如何将这个想法转化为一个功能齐全的移动应用。通过通俗易懂的语言和实际代码示例,本文旨在为初学者提供一个清晰的路径,帮助他们理解移动应用开发的核心概念。无论你是编程新手还是有经验的开发者,这篇文章都将为你提供新的视角和深入的理解。让我们一起踏上这段旅程,探索移动应用开发的世界,发现它如何与我们的生活紧密相连。
35 1
|
2月前
|
IDE 开发工具 Android开发
探索移动应用开发:从概念到实战
【10月更文挑战第35天】在数字化时代的浪潮中,移动应用已成为我们日常生活的一部分。它们不仅改变了我们的沟通、工作和娱乐方式,还不断推动着技术和创新的边界。本文将从初学者的角度出发,介绍移动应用开发的基本概念、主要平台、以及如何将一个想法转化为实际可用的应用。我们将探讨移动操作系统的差异,并深入理解Android和iOS的开发环境。通过简单的代码示例,我们将展示如何在Android平台上创建一个简单的“Hello World”应用,为有志于进入这一领域的新手提供实用的起点。
|
3月前
|
存储 前端开发 JavaScript
前端技术深度探索:从基础到现代框架的实践之旅
前端技术深度探索:从基础到现代框架的实践之旅
66 3
|
3月前
|
设计模式 开发框架 开发工具
深入理解移动应用开发:从概念到实践
【9月更文挑战第30天】在这篇文章中,我们将深入探讨移动应用开发的各个方面。我们将从移动应用开发的基本概念开始,然后逐步深入到具体的技术实现。我们将讨论移动操作系统的基础知识,包括Android和iOS的架构和特性。然后,我们将深入探讨移动应用开发的关键技术,包括编程语言、开发框架和应用设计模式。我们还将提供一些代码示例,以帮助读者更好地理解和掌握这些概念和技术。最后,我们将讨论移动应用开发的未来趋势和挑战。
135 6
|
3月前
|
设计模式 前端开发 JavaScript
深入探索研究MVVM架构设计
【10月更文挑战第7天】
61 0
|
4月前
|
前端开发 Android开发 开发者
探索移动应用开发之旅:从概念到上线
【9月更文挑战第13天】在数字化时代的浪潮中,移动应用已成为连接用户与服务的重要桥梁。本文将引导读者了解移动应用开发的核心要素,包括设计原则、开发流程、操作系统选择、以及如何将一个想法转化为现实中的应用。我们将通过实际案例,探讨如何在竞争激烈的应用市场中突围而出,并确保应用的可持续发展。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和启示。
44 4
|
4月前
|
Java 测试技术 Android开发
移动应用开发之旅:从概念到现实
【9月更文挑战第7天】在数字化的浪潮中,移动应用已成为我们生活的一部分。本文将引导你了解移动应用开发的核心概念、操作系统的选择以及如何将一个创意转化为现实中可用的应用。我们将一起探索这个过程,并揭示背后的技术细节。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和实用的知识。
38 2
|
5月前
|
移动开发 测试技术 开发工具
探索移动应用开发之旅:从概念到实战
【8月更文挑战第29天】在数字化时代的潮流中,移动应用已成为我们日常生活和工作中不可或缺的一部分。本文将引导读者了解移动应用的开发流程,包括设计思路、开发工具的选择以及操作系统的基本知识。我们将通过实际案例,深入探讨如何将一个想法转化为现实中的应用,同时确保内容的通俗易懂和结构的清晰性,为初学者提供一扇进入移动开发世界的大门。
39 1