模块化、MVC化、对象化、类化

模块化、MVC化、对象化、类化

简介

记录由一坨很乱的代码到很简洁有条理的代码的过程。

很乱的代码–>模块化–>MVC化–>对象化–>类化

代码

代码地址

代码范围:从 模块化message的类化

1.很乱的一坨代码

简述

一坨代码写在一起,各种全局变量,容易互相覆盖,而且代码很乱,没条理。

关键

变量 + 函数 + 函数调用

模块化

简述

把一堆各种功能的代码分成各种js文件,例如:run.js、print.js,每个js文件用立即执行函数实现局部变量。

关键

立即执行函数

代码

index.html

<script src="run.js"></script>
<script src="print.js"></script>

print.js

! function () {
    // 原本功能的代码
    var abc = 100

    function hehe() {
        console.log(abc += 1)
    }
    hehe()
}.call()

2.模块之间沟通共享

简述

多个模块之间可能需要互相沟通数据,此时需要通过闭包实现。

关键

闭包

代码

闭包

// 闭包
function bibao() {
    var abc = 100

    function hehe() {
        console.log(abc += 1)
    }

    return hehe
}

// 其他人使用这个闭包。能用hehe函数给abc+1,但是完全不知道abc的值。
var usebibao = bibao()
usebibao()

立即执行函数+闭包

! function () {
    var abc = 100

    window.hehe = function () {
        console.log(abc += 1)
    }
}.call();

// 其他人能使用window.hehe函数给abc+1,但是完全不知道abc的值。
window.hehe()

3.vc化

简述

引入MVC思想,使得代码更有组织,但是前端在没有操作数据时,Model是没有的,所以VC化很常见。

关键

把代码归类,html相关的基本属于view,剩下的就是controller。

代码

! function () {
    var view = document.querySelector('.className')
    var controller = function (view) {
        var viewSon = view.querySelector('.className')
        console.log(view)
        console.log(viewSon)
    }
    controller(view)
}.call()

4.对象化

简述

把代码对象化。

关键

把相关的函数、变量挂到controller的属性。

注意:使用this要注意this被监听函数修改为触发事件的对象,可以用箭头函数修正,箭头函数的this会就进取。

代码

! function () {
    var view = document.querySelector('.className')

    var controller = {
        view: null,
        viewSon: null, // viewSon是saySon函数需要的,也要初始化
        init: function (view) {
            this.view = view
            this.viewSon = this.view.querySelector('.className')
            this.hehe()
            this.saySon()
        },
        hehe: function () {
            var view = this.view
            console.log(view)
        },
        saySon: function () {
            console.log(this.viewSon)
        },
    }

    controller.init.call(controller, view)
}.call()

// 运行过程:
// 1.controller.init.call(controller, view) 把controller和外面的变量view传进init函数里去
// 2.this.view = view 把变量view赋值给controller.view
// 3.this.hehe() 把controller传进hehe函数里去
// 4.var view = this.view 声明一个view变量,controller.view赋值给这个变量
// 5.console.log(view) 把view打印出来。
// 整个过程中 this 一直都是controller,
// 外面的变量view赋值给了controller.view
// controller.view又赋值给了hehe函数里新声明的view
// 最后console.log(view)把hehe函数里的view打印出来

// 写法流程:
// 1.把controller写成一个对象
// 2.controller需要一个view、init、执行函数hehe
// 3.init把需要执行的函数hehe和view关联起来
// 4.init调用,把外面的view交给controller,并调用hehe函数,hehe函数就运行成功

5.MVC化

简述

对于有数据操作的代码,还要在VC化的基础上,把M分离出来。

关键

一般VC化后,从controller里把数据相关的函数拿出来放进Model里就行了。

注意:使用this要注意this被监听函数修改为触发事件的对象,可以用箭头函数修正,箭头函数的this会就进取。

代码

模块化

// 留言板-模块化.js
! function () {
    let messageList = document.querySelector('.messageList')
    let postMessageForm = document.querySelector('.postMessageForm')
    AV.init({
        appId: "XXXXXX",
        appKey: "XXXXXX",
    });
    loadMessage()
    bindEvents()

    function loadMessage() {
        var query = new AV.Query('message');
        query.find()
            .then(function (message) {
                let array = message.map((item) => item.attributes)
                array.forEach((item) => {
                    let li = document.createElement('li')
                    li.innerText = `${item.name}:${item.content}`
                    messageList.append(li)
                })
            })
    }

    function bindEvents() {
        postMessageForm.addEventListener('submit', function (eee) {
            eee.preventDefault() // 阻止表单提交默认刷新页面事件
            saveMessage()
        })
    }

    function saveMessage() {
        let name = postMessageForm.querySelector('input[name=name]').value
        let content = postMessageForm.querySelector('input[name=content]').value
        // leancloud 提供的保存对象的代码
        var Message = AV.Object.extend('message');
        var message = new Message();
        message.set('name', name);
        message.set('content', content);
        message.save()
            .then(function (object) {
                let li = document.createElement('li')
                li.innerText = `${object.attributes.name}:${object.attributes.content}`
                messageList.append(li)
                postMessageForm.querySelector('input[name=content]').value = ''
            })
    }
}.call()

VC化

// 留言板-VC化.js
! function () {
    var view = document.querySelector('.message')

    var controller = {
        view: null,
        messageList: null,
        postMessageForm: null,
        init: function (view) {
            this.view = view
            this.messageList = this.view.querySelector('.messageList')
            this.postMessageForm = this.view.querySelector('.postMessageForm')
            this.initAV()
            this.loadMessage()
            this.bindEvents()
        },
        initAV: function () {
            AV.init({
                appId: "XXXXXX",
                appKey: "XXXXXX",
            });
        },
        loadMessage: function () {
            var query = new AV.Query('message');
            query.find()
                .then((message) => {
                    let array = message.map((item) => item.attributes)
                    array.forEach((item) => {
                        let li = document.createElement('li')
                        li.innerText = `${item.name}:${item.content}`
                        this.messageList.append(li)
                    })
                })
        },
        bindEvents: function () {
            this.postMessageForm.addEventListener('submit', (eee) => {
                eee.preventDefault() // 阻止表单提交默认刷新页面事件
                this.saveMessage()
            })
        },
        saveMessage: function () {
            let name = this.postMessageForm.querySelector('input[name=name]').value
            let content = this.postMessageForm.querySelector('input[name=content]').value
            // leancloud 提供的保存对象的代码
            var Message = AV.Object.extend('message');
            var message = new Message();
            message.set('name', name);
            message.set('content', content);
            message.save()
                .then((object) => {
                    let li = document.createElement('li')
                    li.innerText = `${object.attributes.name}:${object.attributes.content}`
                    this.messageList.append(li)
                    this.postMessageForm.querySelector('input[name=content]').value = ''
                })
        },
    }
    controller.init(view)
}.call()

MVC化

// 留言板-MVC化.js
! function () {
    var view = document.querySelector('.message')

    var model = {
        init: function () {
            AV.init({
                appId: "XXXXXX",
                appKey: "XXXXXX",
            });
        },
        fetch: function () {
            var query = new AV.Query('message');
            return query.find()
        },
        save: function (name, content) {
            var Message = AV.Object.extend('message');
            var message = new Message();
            message.set('name', name);
            message.set('content', content);
            return message.save()
        },
    }

    var controller = {
        view: null,
        model: null,
        messageList: null,
        postMessageForm: null,
        init: function (view, model) {
            this.view = view
            this.model = model
            this.messageList = this.view.querySelector('.messageList')
            this.postMessageForm = this.view.querySelector('.postMessageForm')
            this.model.init()
            this.loadMessage()
            this.bindEvents()
        },
        loadMessage: function () {
            this.model.fetch().then((message) => {
                let array = message.map((item) => item.attributes)
                array.forEach((item) => {
                    let li = document.createElement('li')
                    li.innerText = `${item.name}:${item.content}`
                    this.messageList.append(li)
                })
            })
        },
        bindEvents: function () {
            this.postMessageForm.addEventListener('submit', (eee)=> {
                eee.preventDefault() // 阻止表单提交默认刷新页面事件
                this.saveMessage()
            })
        },
        saveMessage: function () {
            var name = this.postMessageForm.querySelector('input[name=name]').value
            var content = this.postMessageForm.querySelector('input[name=content]').value
            // leancloud 提供的保存对象的代码
            this.model.save(name, content).then((object) => {
                let li = document.createElement('li')
                li.innerText = `${object.attributes.name}:${object.attributes.content}`
                this.messageList.append(li)
                this.postMessageForm.querySelector('input[name=content]').value = ''
            })
        },
    }
    controller.init(view, model)
}.call()

6.类化

简述

把MVC化的代码公共部分提取出来,分成3个js文件,其他文件再去使用这3个MVC文件。

关键

1.把公有的代码拿出来做成一个object对象

2.私有的代码作为参数以options对象传进MVC函数

3.object作为this去调用options的私有函数init

4.遍历options的属性拿到其余的属性

5.返回object,它有公有属性,也有私有属性。

代码

以message.js为例。

View.js

// 1.改造前
var view = document.querySelector('.message')
// 私有部分是'.message'

// 2.类化
window.View = function (selector) {
    return document.querySelector(selector)
}
// 3.使用方
var view = View('.message')

Model.js

// 1.改造前
var model = {
    init: function () {
        AV.init({
            appId: "mJuVhxO68GtStDWtrhFJUX8t-gzGzoHsz",
            appKey: "heQIds6bW7KitjLNGrrYGYv8",
        });
    },
    fetch: function () {
        var query = new AV.Query('message');
        return query.find()
    },
    save: function (name, content) {
        var Message = AV.Object.extend('message');
        var message = new Message();
        message.set('name', name);
        message.set('content', content);
        return message.save()
    },
}
// 私有部分是'message'

// 2.类化
window.Model = function (options) {
    let resourceName = options.resourceName
    return {
        init: function () {
            AV.init({
                appId: "mJuVhxO68GtStDWtrhFJUX8t-gzGzoHsz",
                appKey: "heQIds6bW7KitjLNGrrYGYv8",
            });
        },
        fetch: function () {
            var query = new AV.Query(resourceName);
            return query.find()
        },
        save: function (object) {// 把原本的name和content合成一个object
            var Message = AV.Object.extend(resourceName);
            var message = new Message();
            message.set('name', object.name);
            message.set('content', object.content);
            return message.save()
        },
    }
}
// 3.使用方
var model = Model({resourceName: 'message'})

Controller.js

// 1.改造前
var controller = {
    view: null,
    model: null,
    messageList: null,
    postMessageForm: null,
    init: function (view, model) {
        this.view = view
        this.model = model
        this.messageList = this.view.querySelector('.messageList')
        this.postMessageForm = this.view.querySelector('.postMessageForm')
        this.model.init()
        this.loadMessage()
        this.bindEvents()
    },
    loadMessage: function () {
        this.model.fetch().then((message) => {
            let array = message.map((item) => item.attributes)
            array.forEach((item) => {
                let li = document.createElement('li')
                li.innerText = `${item.name}:${item.content}`
                this.messageList.append(li)
            })
        })
    },
    bindEvents: function () {
        this.postMessageForm.addEventListener('submit', (eee) => {
            eee.preventDefault() // 阻止表单提交默认刷新页面事件
            this.saveMessage()
        })
    },
    saveMessage: function () {
        var name = this.postMessageForm.querySelector('input[name=name]').value
        var content = this.postMessageForm.querySelector('input[name=content]').value
        // leancloud 提供的保存对象的代码
        this.model.save(name, content).then((object) => {
            let li = document.createElement('li')
            li.innerText = `${object.attributes.name}:${object.attributes.content}`
            this.messageList.append(li)
            this.postMessageForm.querySelector('input[name=content]').value = ''
        })
    },
}
// 私有部分是messageList、postMessageForm、loadMessage、bindEvents、saveMessage
// 公有部分是view、model、init的一部分


// 2.类化
window.Controller = function (options) {
    // 拿到私有的init
    var init = options.init

    let object = {
        view: null,
        model: null,
        init: function (view, model) {
            this.view = view
            this.model = model
            this.model.init()
            // 调用私有的init
            init.call(this, view, model)
            // 相当于 options.init.call(object, view, model)
            this.bindEvents()
        },
    }
    // 拿到init以外的私有属性
    for (let key in options) {
        if (key !== 'init') {
            object[key] = options[key]
        }
    }
    return object
}

// 3.使用方
var controller = Controller({
    init: function (view, model) {
        this.messageList = this.view.querySelector('.messageList')
        this.postMessageForm = this.view.querySelector('.postMessageForm')
        this.loadMessage()
    },
    loadMessage: function () {
        this.model.fetch().then((message) => {
            let array = message.map((item) => item.attributes)
            array.forEach((item) => {
                let li = document.createElement('li')
                li.innerText = `${item.name}:${item.content}`
                this.messageList.append(li)
            })
        })
    },
    bindEvents: function () {
        this.postMessageForm.addEventListener('submit', (eee) => {
            eee.preventDefault() // 阻止表单提交默认刷新页面事件
            this.saveMessage()
        })
    },
    saveMessage: function () {
        var name = this.postMessageForm.querySelector('input[name=name]').value
        var content = this.postMessageForm.querySelector('input[name=content]').value
        // leancloud 提供的保存对象的代码
        this.model.save({
            'name': name,
            'content': content
        }).then((object) => {
            let li = document.createElement('li')
            li.innerText = `${object.attributes.name}:${object.attributes.content}`
            this.messageList.append(li)
            this.postMessageForm.querySelector('input[name=content]').value = ''
        })
    },
})
controller.init(view, model)