侧边栏壁纸
博主头像
woku博主等级

成功的路上并不拥挤

  • 累计撰写 50 篇文章
  • 累计创建 13 个标签
  • 累计收到 3 条评论
vue

MVC

woku
2022-03-07 / 0 评论 / 0 点赞 / 69 阅读 / 4,837 字

什么是MVC

在架构层面的一种设计思想

后端中MVC

全称作用
MModel(数据模型层)操作数据库,包括数据库的增删改查
VView(视图层)显示视图或视图模板
CController(控制器层)逻辑层:数据和视图的关联挂载和基本的逻辑操作。API层:前端通过异步请求访问的API对应控制器层的一个方法

MVC的这种设计思想,将整个架构分为三层,三层的关联:

  • 服务端渲染

    View需要数据 -> Controller层找对应方法 -> 调用Model层方法 -> 操作数据库获取数据 -> 数据返回到Controller -> render到View

  • 前端渲染

    异步请求URL -> Controller层对应方法 -> Model层中方法 -> 操作数据库获取数据 -> 返回到Controller方法 -> 相应前端

前端中MVC

全称作用
MModel(数据层)提供视图所需要的数据,数据与视图的关联
VView(视图层)视图模板和视图渲染
CController(事件层)管理事件逻辑

MVC不是解决DOM操作的问题,是为了把项目的逻辑分离,让各个层独立开发,更好的维护和扩展。

案例(前端)

运用MVC,实现加减乘除计算器

划分三层

  1. Model层

    提供数据:数据a,数据b,运算符s

    数据与视图管理:监听数据变化,重新渲染视图

  2. View层:

    视图模板:template

    视图渲染:render

  3. Controller层

    事件绑定,事件触发后,Model里面的数据更新

代码

新建html文件以及入口文件

    <div id="app"></div>
    <script src="./src/App.js" type="module">  
    </script>

Model

(function() {
    function init() {
        model.init() // 数据的初始化和数据的代理
    }
    var model = {
        data: {
            a: 0,
            b: 0,
            s: '+',
            r: 0
        },
        init: function() {
            var _this = this
            for (var k in this.data) {
                (function(k) {
                    Object.defineProperty(model, k, {
                        get: function() {
                            return _this.data[k]
                        },
                        set: function(val) {
                            model.data[k] = val
                        }
                    })
                })(k)
            }
        }
    }
    init()
})()

Model + View

(function() {
    function init() {
        model.init()
        view.render()
    }
    var model = {
        data: {
            a: 0,
            b: 0,
            s: '+',
            r: 0
        },
        init: function() {
            var _this = this
            for (var k in this.data) {
                (function(k) {
                    Object.defineProperty(model, k, {
                        get: function() {
                            return _this.data[k]
                        },
                        set: function(val) {
                            model.data[k] = val
                            // 数据发生改变,视图重新渲染
                            view.render({[k]: val})
                        }
                    })
                })(k)
            }
        }
    }
    var view = {
        el: '#app',
        template: `
          <span class="cal-a">{{ a }}</span>
          <span class="cal-s">{{ s }}</span>
          <span class="cal-b">{{ b }}</span>
          <span>=</span>
          <span class="cal-r">{{ r }}</span>
          <p>
            <input type="text" placeholder="number a" class="cal-input a"/>
            <input type="text" placeholder="number b" class="cal-input b"/>
          </p>
          <p>
            <button>+</button>
            <button>-</button>
            <button>*</button>
            <button>/</button>
          </p>
        `,
        render: function(data) {
            // 数据舒适渲染
            if (!data) {
                this.template = this.template.replace(/\{\{(.*?)\}\}/g, function(node, key) {
                    return model[key.trim()]
                })
                var el = document.createElement('div')
                el.innerHTML = this.template
                document.querySelector(this.el).appendChild(el)
            } else { // 有数据要更新
                for (var key in data) {
                    document.querySelector('.cal-' + key).textContent = data[key]
                }
            }
        }
    }
    init()
})()

Model + View + Controller

(function() {
    function init() {
        model.init()
        view.render()
        controller.init()
    }
    var model = {
        data: {
            a: 0,
            b: 0,
            s: '+',
            r: 0
        },
        init: function() {
            var _this = this
            for (var k in this.data) {
                (function(k) {
                    Object.defineProperty(model, k, {
                        get: function() {
                            return _this.data[k]
                        },
                        set: function(val) {
                            model.data[k] = val
                            // 数据发生改变,视图重新渲染
                            view.render({[k]: val})
                        }
                    })
                })(k)
            }
        }
    }
    var view = {
        el: '#app',
        template: `
          <span class="cal-a">{{ a }}</span>
          <span class="cal-s">{{ s }}</span>
          <span class="cal-b">{{ b }}</span>
          <span>=</span>
          <span class="cal-r">{{ r }}</span>
          <p>
            <input type="text" placeholder="number a" class="cal-input a"/>
            <input type="text" placeholder="number b" class="cal-input b"/>
          </p>
          <p>
            <button>+</button>
            <button>-</button>
            <button>*</button>
            <button>/</button>
          </p>
        `,
        render: function(data) {
            // 数据舒适渲染
            if (!data) {
                this.template = this.template.replace(/\{\{(.*?)\}\}/g, function(node, key) {
                    return model[key.trim()]
                })
                var el = document.createElement('div')
                el.innerHTML = this.template
                document.querySelector(this.el).appendChild(el)
            } else { // 有数据要更新
                for (var key in data) {
                    document.querySelector('.cal-' + key).textContent = data[key]
                }
            }
        }
    }
    var controller = {
        init: function() {
            var inputDoms = document.querySelectorAll('.cal-input'),
                btnDoms = document.querySelectorAll('button'),
                btnItem,
                inputItem
            for (var i = 0; i < inputDoms.length; i++) {
                inputItem = inputDoms[i]
                inputItem.addEventListener('input', this.inputHandle, false)
            }
            for (var i = 0; i < btnDoms.length; i++) {
                btnItem = btnDoms[i]
                btnItem.addEventListener('click', this.clickHandle, false)
            }
        },
        clickHandle: function(e) {
            var type = e.target.textContent
            model.s = type
            model.r = eval('model.a' + model.s + 'model.b')
        },
        inputHandle: function(e) {
            var tar = e.target,
                val = Number(tar.value),
                filed = tar.className.split(' ')[1]
            // 更新了model中的数据,view会更新
            model[filed] = val
            model.r = eval('model.a' + model.s + 'model.b')
            // with(model) {
            //     r = eval('a' + s + 'b')
            // }
            // with严格模式下禁止使用
        }
    }
    init()
})()

效果:

Model层主要是管理数据,和对数据的劫持监听

View层主要是做模板的定义和模板的重新渲染

Controller层主要是做了事件的绑定和定义事件处理函数逻辑

每个层做每个层的事情

Controller -> Model -> View (Controller里改变了数据,数据改变,视图更新)

View -> Controller -> Model (视图变化,经过Controller层,Controller改变数据)

MVC的问题

从上面代码来看,MVC这种分层模式从横向上来看是非常合适的,但是从纵向来看就会有问题

Model层,里面是定义数据的地方,将数据劫持的方法放在了Model里面

View层,里面是定义模板的地方,将视图的render方法放在了View里面

Controller层,里面是定义事件处理函数,将绑定事件的逻辑放在了Controller里面

这样会出现驱动不集中的问题,

我们把数据,HTML模板,事件处理函数看成是上层用户定义的,把数据劫持,render,事件绑定看成是驱动的一个能力,

那么可以看出,这些驱动分部在M,V,C三层,不集中

MVVM的由来

MVVM解决了MVC的驱动不集中的问题,下一章详细讲解。。。

0

评论区