前端 MVC、MVVM 与面向对象

2018-08-19  本文已影响52人  千反田爱瑠爱好者

按照《前端MVC与模块化》中的方法把各模块代码分成MVC三层,仍然存在一些问题,如公共方法无法复用、每个模块MVC中都有大量重复代码:

model.js

window.Model = Model(options){
    this.data = options.data
    this.resource = options.resource
}
window.Model.prototype.fetch = function(id){
    return axios.get(`/${this.resource}s/${id}`).then((response) => {
        this.data = response.data
        return response
      })
}
window.Model.prototype.update = function(data){
    let id = this.data.id
    return axios.put(`/${this.resource}s/${id}`, data).then((response) => {
        this.data = response.data 
        return response
    })
}

view.js

window.View = function ({el, template}){
    this.el = el
    this.template = template
}
window.View.prototype.render = function(data){
    let html = this.template
    for(let key in data){
      html = html.replace(`__${key}__`, data[key])
    }
    $(this.el).html(html)
}

controller.js

window.Controller = function (options) {
    let init = options.init
    let object = {
        init: function (view, model) {
            this.view.render(this.model.data)
            init.call(view, model)
            options.bindEvents.call()
        }
    }
    for (let key in options) {    // 写入实现对象特有的方法
        object[key] = options[key]
    }
    return object
}

实现一个功能模块:

!function () {
    let model = new Model({
        data: {
            name: '',
            number: 0,
            id: ''
        },
        resource: 'Message'
    })
    let view = View({
        el: '.messageBoard',
        template: `
                <div>
                    书名:《__name__》
                    数量:<span id=number>__number__</span>
                </div>
                <div>
                    <button id="addOne">加1</button>
                    <button id="minusOne">减1</button>
                    <button id="reset">归零</button>
                </div>
        `
    })
    let controller = Controller({
        init: function(view, model) {
            this.model.fetch(1).then(() => {
                this.view.render(this.model.data)
            })
        },
        bindEvents: function() {
            $(this.view.el).on('click', '#reset', this.reset.bind(this))
            $(this.view.el).on('click', '#addOne', this.addOne.bind(this))
            // ...
        },
        addOne: function() {
            var oldNumber = $('#number').text()
            var newNumber = oldNumber - 0 + 1
            this.model.update({
                number: newNumber
            }).then(() => {
                this.view.render(this.model.data)
            })
        },
        reset() {
            this.model.update({
                number: 0
            }).then(() => {
                this.view.render(this.model.data)
            })
        },
    })
    controller.init({view: view, model: model})
}.call()

MVVM

使用Vue自动实现MVC:


MVVM

其中ViewModel实现了MVC中Controller的功能:

html

<div id="app">
</div>

script

    initData()

    // MVC类(C封装在V内)
    function Model(options) {
        this.data = options.data
        this.resource = options.resource
    }
    Model.prototype.fetch = function (id) {
        return axios.get(`/${this.resource}s/${id}`).then((response) => {
            this.data = response.data
            return response
        })
    }
    Model.prototype.update = function (data) {
        let id = this.data.id
        return axios.put(`/${this.resource}s/${id}`, data).then((response) => {
            this.data = response.data
            return response
        })
    }

    // 对象
    let model = new Model({
        data: {
            name: '', number: 0, id: ''
        },
        resource: 'book'
    })

    let view = new Vue({
        el: '#app',
        data: {
            book: {
                name: '未命名',
                number: 0,
                id: ''
            },
            n: 1
        },
        template: `
        <div>
            <div>
                书名:《{{book.name}}》
                数量:<span id=number>{{book.number}}</span>
            </div>
            <div>
                <input v-model="n" /> N 的值是 {{n}}
            </div>
            <div>
                <button v-on:click="addOne">加N</button>
                <button v-on:click="minusOne">减N</button>
                <button v-on:click="reset">归零</button>
            </div>
        </div>
        `,
        created() {
            model.fetch(1).then(() => {
                this.book = model.data
            })
        },
        methods: {
            addOne() {
                model.update({
                    number: this.book.number + (this.n - 0)
                }).then(() => {
                    this.view.book = this.model.data
                })
            },
            minusOne() {
                model.update({
                    number: this.book.number - (this.n - 0)
                }).then(() => {
                    this.view.book = this.model.data
                })
            },
            reset() {
                model.update({
                    number: 0
                }).then(() => {
                    this.view.book = this.model.data
                })
            },
        }
    })

    function initData() {
        let book = {
            name: 'JavaScript 高级程序设计', number: 2, id: 1
        }
        axios.interceptors.response.use(function (response) {
            let {
                config: {method, url, data}
            } = response
            if (url === '/books/1' && method === 'get') {
                response.data = book
            } 
            else if (url === '/books/1' && method === 'put') {
                data = JSON.parse(data)
                Object.assign(book, data)
                response.data = book
            }
            return response
        })
    }

this 关键字

function X() {
    return object = {
        name: 'object',
        options: null,
        f1(x) {
            this.options = x    // 此处x实际上是外部传入的第二个参数,即options
            this.f2()
        },
        f2() {
            this.options.f2.call(this)    // 此处this是x,即'object'
        }
    }
}

var options = {
    name: 'options',
    f1(){},
    f2(){
        console.log(this)    // 此处this是由外部传入,即'object'
    }
}

var x = X()
x.f1(options)    // x.f1.call(x, options)

call、apply与bind

var s = {
    a:1,
    b:2,
    add(name) {
        console.log(this.a + this.b)
        console.log(name)
    }
}
var a = {
    a: 2, b: 2,
}
var b = {
    a: 4, b: 2,
}
var c = {
    a: 5, b: 6,
}
s.add.call(a,"call")
s.add.apply(b,["apply"])  
s.add.bind(c,"bind")()    // 等价于s.add.bind(c)("bind")

new 关键字

function Human(options) {    // Human类的构造函数,传入对象必须包括name、city参数
    this.name = options.name    
    this.city = options.city
}

Human.prototype = {
    constructor: Human,    // 记录通过new Human()创建的对象类型即为Human
    species: function(){},
    walk: function(){},
    useTools: function(){}
}

var human = new Human({name:'ywh', city: 'gz'})
human.__proto__                          // 对应的对象(即原型)具有species、walk和useTools这几个属性
human.__proto__.constructor === Human    // 表示human的类型为Human
上一篇 下一篇

猜你喜欢

热点阅读