美文网首页
MVC之V和C

MVC之V和C

作者: lyp82nkl | 来源:发表于2019-06-25 01:51 被阅读0次
    什么是MVC

    视图(View):只负责渲染 HTML(可接受一个 data 来定制数据)
    控制器(Controller):负责调度 model 和 view
    模型(Model):只负责存储数据、请求数据、更新数据



    View 传送指令到 Controller
    Controller 完成业务逻辑后,要求 Model 改变状态
    Model 将新的数据发送到 View,用户得到反馈

    1.模块化你的js代码

    将同一模块的js代码放在同一个文件夹里并正确命名,用立即执行函数封装代码,防止出现全局变量

     <!-- 模块化 -->
        <script src="./js/auto-slide-up.js"></script>
        <script src="./js/init-swiper.js"></script>
        <script src="./js/smoothly-navigation.js"></script>
        <script src="./js/sticky-topbar.js"></script>
    

    2.设置 V 和 C

    简单区分出 V 和 C

    找到 js 模块对应的 html 模块,即是 view
    view 的作用是告诉js哪一部分是对应模块的 view
    以轮播模块为例

     <div id="mySlides">
            <div class="swiper-container">
                <!-- Additional required wrapper -->
                <div class="swiper-wrapper">
                    <!-- Slides -->
                    <img src="./img/works/nav-page.jpg" class="swiper-slide">
                    <img src="./img/works/canvas.jpg" class="swiper-slide">
                    <img src="./img/works/apple-style-slides.jpg" class="swiper-slide">
                </div>
                <!-- If we need pagination -->
                <div class="swiper-pagination"></div>
    
            </div>
            <!-- If we need navigation buttons -->
            <div class="swiper-button-prev"></div>
            <div class="swiper-button-next"></div>
            </div>
    
    在 js 中声明一个 view 作为 js 模块的 view,如轮播模块的 view 为 #mySlides
    声明一个 controller 是 view 的函数
    !function(){
        var view = document.querySelector('#mySlides')
        var controller = function(view){
            var mySwiper = new Swiper(view.querySelector('.swiper-container'), {
                loop: true,
                // If we need pagination
                pagination: {
                    el: '.swiper-pagination',
                },
            
                // Navigation arrows
                navigation: {
                    nextEl: '.swiper-button-next',
                    prevEl: '.swiper-button-prev',
                }
            })
        }
        controller(view)
    }.call()
    

    再简化一下

    用另一个模块 topNavBar 举例(可以看到每个模块结构是一致的)

    ! function () {
        var view = document.querySelector('#topNavBar')
        //把 controller 变成对象
        var controller = {
            //把函数放到 init 里(init 即是初始化)
            init: function (view) {
                window.addEventListener('scroll', function (x) {
                    if (window.scrollY > 0) {
                        topNavBar.classList.add('sticky')
                    } else {
                        topNavBar.classList.remove('sticky')
                    }
                })
            }
        }
        //此时 controller(view) 就变成了 controller.init(view)
        controller.init(view)
    }.call()
    

    下面是关键

    ! function () {
        var view = document.querySelector('#topNavBar')
        var controller = {
            //开始 controller 有个空的 view     
            view: null,
            //有个初始化函数
            init: function (view) {
                //把 view 存到 controller 的 view 里
                this.view = view
                //下面代码 this.bindEvents.call(this)
                this.bindEvents()
            },
            //绑定事件
            bindEvents: function () {
                //所以这里的 this 就是上面的 this
                //上面的 this 就等于 controller.init(view)
                //controller.init(view) 的 this 就是 controller
                var view = this.view
                window.addEventListener('scroll', function (x) {
                    if (window.scrollY > 0) {
                        topNavBar.classList.add('sticky')
                    } else {
                        topNavBar.classList.remove('sticky')
                    }
                })
            }
        }
        //下面代码等价于controller.init.call(controller,view) 即 this 就是controller
        controller.init(view)
    }.call()
    

    controller 有个 view,有个初始化函数,并可以绑定事件
    下面优化绑定事件函数内部代码,让其只起绑定事件的作用

    window.addEventListener('scroll', function (x) {
        if (window.scrollY > 0) {
            topNavBar.classList.add('sticky')
        } else {
            topNavBar.classList.remove('sticky')
        }
    })
    

    由于 addEventListener 里面的 this 代表用户触发的元素
    但是我们希望 this 与原来一致

    解决方法一:用 bind()

    window.addEventListener('scroll', function (x) {
        if (window.scrollY > 0) {
            topNavBar.classList.add('sticky')
        } else {
            topNavBar.classList.remove('sticky')
        }
    }).bind(this)
    

    解决方法二:箭头函数

    由于箭头函数没有 this ,所以当我们在其内部使用 this 默认就是外部的 this。
    可以说箭头函数内外 this 不变,我们的目的就是让函数内外 this 不变
    然后将 addClass 和 remove Class 事件也用各自的函数分隔开,同样用 this 和 view 串起来
    完整代码

    ! function () {
        var view = document.querySelector('#topNavBar')
        var controller = {
            view: null,
            init: function (view) {
                this.view = view
                this.bindEvents()
            },
            bindEvents: function () {
                var view = this.view
                window.addEventListener('scroll', (x) =>{
                    if (window.scrollY > 0) {
                        this.active()
                    } else {
                        this.deactive()
                    }
                })
            },
            active:function(){
                this.view.classList.add('sticky')
            },
            deactive:function(){
                this.view.classList.remove('sticky')
            }
        }
        controller.init(view)
    }.call()
    

    总结

    所有模块结构:
    在立即执行函数内部
    有个 view
    有个 controller
    controller 操作 view
    将复杂的代码模块化,然后通过对象 controller 将 view 的函数通过 this 串起来,使得每一个 view 的函数都可以被 controller 操控

    相关文章

      网友评论

          本文标题:MVC之V和C

          本文链接:https://www.haomeiwen.com/subject/enhzqctx.html