JS中的MVC

MVC是什么?
MVC是一种架构模式,它将应用抽象为3个部分:模型(Model)、视图(View)、控制器(Controller)。
这里写图片描述
一个事件发生的过程(通信单向流动)
1、用户在视图V上与应用程序交互
2、控制器C触发相应的事件,要求模型M改变状态(读写数据)
3、模型M将数据发送到视图V,更新数据,展现给用户。
在JS的传统开发模式中,大多基于事件驱动的:
1、hash驱动
2、DOM事件用来驱动视图
3、模型事件用来驱动模型和模型结合
所以JS中的MVC的特点是:单向流动、事件驱动

一、模型
模型存放着应用的所有数据对象,比如例子中的store模型,存放着每一条记录与之有关的逻辑。模型有对数据直接访问的权利,不依赖于视图和控制器,不关心页面如何显示及如何被操作。
数据是面向对象的,当控制器要求模型读写数据时,模型就将数据包装成模型实例,任何定义在这个数据模型上的函数或逻辑都可以直接被调用。
模型不关心不包含视图和控制器的逻辑,它们应该是相互解耦的,模型与视图的耦合显然是违反MVC架构原则,但往往我们有时候因为业务关系而无法完全解耦。
模型表现了领域特定的数据,当一个模型有所改变的时候,它会通知它的观察者。

二、视图
视图是呈现给用户的,是用户交互的第一入口,他定义配置管理者每个页面相应的模板与组件,表现为一个模型的当前状态。视图通过观察者模式监听模型层上的数据改变以获得最新的数据,来呈现最新的页面,所以页面首次加载时往往是从接收模型的数据开始。实时的更新HTML页面,包括一些事件的注册或者ajax请求操作都是放在视图层来完成。

三、控制器
控制器是模型和视图之间的桥梁,集中式的配置和管理事件分发、模型分发、视图分发、还用来权限控制、异常处理等。我们的应用中往往是有多个控制器的。
页面加载完成后,控制器会监听视图的用户交互,一旦用户发生交互时,控制其作出对视图的选择,触发控制器的事件处理机制,去派发新的事件,通知模型更新数据。
控制器接受用户的操作,最主要的是视图层的事件,然后调用模型或视图去完成用户的操作。比如当页面上触发一个事件,控制器不输出任何东西及对页面做任何处理,他只是接受请求并决定调用模型中的哪个方法去处理请求,然后在调用哪个视图中的方法来显示返回的数据。

ex:todoList
用原生js写的todoList,点击输入文字点击确定就添加,删除是直接点击该行信息。
思路:
1、V层定义配置了一个显示数据的字符串模板,同时定义一个订阅者的回调函数render()用于页面更新数据。
2、C层监听用户的添加与删除操作,添加是add()函数,它执行了回调函数render,同时向M层写入数据,通知M层改变,删除操作同理。
3、M层是本地存储localStorage。模拟一个存储数据对象的后台模型。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <header>
        <h3>待定事项</h3>
    </header>
    <main>  
        <ul id="todoList"></ul>
        <input type="text" id="content" name="">
        <button id="confirm">确认</button>
    </main>
    <script type="text/javascript">
        (function(){
            const ADD_KEY='_todoList_'
            const Utils={
                //模拟Model(实体模型)
                store(key,data){
                    if(arguments.length>1){
                        return localStorage.setItem(key,JSON.stringify)
                    }else{
                        let storeData=localStorage.getItem(key);
                        return (storeData && JSON.parse(storeData))||[];
                    }                   
                }
            }
            class Todo{
                constructor(id,text=""){
                    this.id=id;
                    this.text=text;
                }
            }
            let App={
                init(){
                    this.todos=Utils.store(ADD_KEY)
                    this.findDom()
                    this.bindEvent()
                    this.render()
                },
                findDom(){
                    this.contextBox=document.querySelector("#content");
                    this.confirm=document.querySelector("#confirm");
                    this.todoList=document.querySelector("#todoList");
                    this.todoListItem=document.getElementsByTagName("li")
                },
                //模拟Controller(业务逻辑层)
                bindEvent(){
                    this.confirm.addEventListener('click',()=>{
                        //要求模型M改变状态,add()函数是写入数据操作
                        this.add()
                    },false)
                },
                //抽象成一个视图
                view(){
                    let fragment=document.createDocumentFragment();
                    fragment="";
                    for(let i=0;i<this.todos.length;i++){
                        fragment+='<li>${this.todos[i].text}</li>'
                    }
                    this.todoList.innerHTML=fragment;
                },
                render(){
                    this.view()
                    Utils.store(ADD_KEY,this.todos)
                },
                getItemIndex(item){
                    let itemIndex;
                    if(item.target.tagName.toLowerCase()==='li'){
                        let arr=Array.prototype.slice.call(this.todoListItem);
                        let index=arr.indexOf(item.target);
                        return itemIndex=index;
                    }
                },
                add(e){
                    let id=Number(new Date());
                    let next=this.contentBox.value();
                    let addTodo=new Todo(id ,text);
                    this.todos.unshift(addTodo);
                    this.render();
                },
                remove(item){
                    let index=this.getItemIndex(item);
                    this.todos.splice(index,1);
                    this.render();
                }
            }
            App.init();
        })()
    </script>
</body>
</html>

MVC槟城把所有精力放在数据处理,尽可能减少对网页元素的处理。对于有一定数量功能的网页,MVC模式下强制规范代码简化减少重复代码,使代码易于补充。

MVC模式的弊端:
1)控制层和视图层耦合,导致没有真正分离和重用
2)在同一业务逻辑下,如果存在多种视图呈现,需要视图定义配置多个模板引擎、数据解析、多次处理数据与页面更新。代码就充满了各种选择器与事件回调。

文章参考于:https://www.cnblogs.com/LIUYANZUO/p/7231703.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值