案例挑战——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
前端技术的演变与实战应用
前端技术的演变与实战应用
|
7月前
|
人工智能 前端开发 测试技术
AI:探究下前端组件化设计的实现方法及其重要性(一)
AI:探究下前端组件化设计的实现方法及其重要性
|
7月前
|
人工智能 缓存 前端开发
AI:探究下前端组件化设计的实现方法及其重要性(二)
AI:探究下前端组件化设计的实现方法及其重要性
|
4月前
|
设计模式 物联网 Android开发
移动应用与系统:探索未来技术的融合之路后端开发中的设计模式探索
【8月更文挑战第21天】随着科技的飞速发展,移动应用和操作系统已经成为我们日常生活中不可或缺的一部分。本文将深入探讨移动应用开发和移动操作系统的相关话题,包括它们的历史、现状以及未来的发展趋势。我们将从移动应用的开发环境、编程语言和工具等方面进行详细的分析,同时也会讨论移动操作系统的特点、优势以及面临的挑战。最后,我们将展望移动应用与系统在未来技术融合中的可能方向和机遇。
132 58
|
28天前
|
存储 缓存 前端开发
前端技术探索:从基础到进阶的旅程
【10月更文挑战第23天】前端技术探索:从基础到进阶的旅程
12 0
|
2月前
|
存储 前端开发 JavaScript
前端技术深度探索:从基础到现代框架的实践之旅
前端技术深度探索:从基础到现代框架的实践之旅
36 2
|
2月前
|
设计模式 前端开发 JavaScript
深入探索研究MVVM架构设计
【10月更文挑战第7天】
28 0
|
4月前
|
Cloud Native Java 开发者
探索后端开发:从基础到高级的演进之路
【8月更文挑战第23天】 在数字时代的浪潮中,后端开发扮演着支撑整个互联网世界运行的关键角色。本文旨在通过浅显易懂的语言,为初学者揭开后端开发的神秘面纱,同时为有一定基础的开发者提供进阶的指引。我们将一起回顾后端技术的演变历程,探讨当下流行的后端框架,并展望未来可能的技术趋势。无论你是编程新手还是资深开发者,这篇文章都将为你的职业发展之路提供宝贵的思考和灵感。
52 3
|
4月前
|
设计模式 存储 前端开发
MVC革命:如何用一个设计模式重塑你的应用架构,让代码重构变得戏剧性地简单!
【8月更文挑战第22天】自定义MVC(Model-View-Controller)设计模式将应用分为模型、视图和控制器三个核心组件,实现关注点分离,提升代码可维护性和扩展性。模型管理数据和业务逻辑,视图负责数据显示与用户交互,控制器处理用户输入并协调模型与视图。通过示例代码展示了基本的MVC框架实现,可根据需求扩展定制。MVC模式灵活性强,支持单元测试与多人协作,但需注意避免控制器过度复杂化。
47 1
|
4月前
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
101 0