什么是设计模式?
** 设计模式(Design pattern)** 是解决软件开发某些特定问题而提出的一些解决方案,也可以理解成解决问题的一些思路。通过设计模式可以帮助我们增强代码的可重用性、可扩充性、 可维护性、灵活性好。我们使用设计模式最终的目的是实现代码的** 高内聚 和 低耦合**。
MVC是什么?
计模式,它通过关注点分离鼓励改进应用程序组织
- M是model数据模型,负责操作数据;
- V是view视图模块负责所有UI界面;
- C 是 Controller,控制器,负责监听用户事件,然后调用 M 和 V 更新数据和视图
const Model= { data:{}, //绑定数据 init: function(){}, //增删改查 add: function(){}, delete: function(){}, get: function(){} } const View={ el:'', //挂载元素 init: function(){}, //初始化 template:'', //模板 render: function(){} //渲染函数 } const controller = { init(): function{}, //初始化 bindEvents: function(){}, //绑定事件 }
EventBus
EventBus 也就是观察者模式,又被称为发布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己
** 常用的事件 **
1、监听事件
eventBus.on()eventBus.on("eventName",callback)
2、触发事件
eventBus.trigger('m:updated')
3、解绑事件
eventBus.off()eventBus.off("eventName",callback)
View = render(data)
以前使用DOM的时候,js是先从页面获取数据,然后改变数据最后再渲染到页面。
而View = render(data)的思想是,数据通过js获取,随后改变js里的数据,再渲染页面。
比起操作DOM,之间render就简单多了,只要改变data就可以得到对应的view。但同时render每次都要重新渲染整个页面,会浪费性能,这个问题可以通过虚拟DOM解决。
表驱动编程
表驱动编程是一种很重要的编程思想,它的理念是从大量相似的代码中抽取出本质的东西,组成哈希表,利用表进行编程,以减少重复代码。
例如:需要给多个元素绑定不同的事件,直觉上我们会一个个地给每一个事件绑定:
$('#el1').on('事件A', fn1) $('#el2').on('事件B', fn2) $('#el3').on('事件C', fn3) $('#el4').on('事件D', fn4) $('#el5').on('事件E', fn5)
一旦重复次数过多,代码就会变得冗余、臃肿。纵观整体,可以发现每行代码最关键的信息其实就是'#el'、'事件'和fn,将关键信息抽离,组成一个对象:
const events = { '#el1 事件A': 'fn1', '#el2 事件B': 'fn2', '#el3 事件C': 'fn3', '#el4 事件D': 'fn4', '#el5 事件E': 'fn5' } const eventFunctions = { //事件处理函数 fn1(){} fn2(){} fn3(){} fn4(){} fn5(){} }
然后创建一个函数,给这些元素绑定相应的事件:
function autoBindEvents(){ for(let key in events){ const spaceIndex = key.indexOf(' ') const element = key.slice(0, spaceIndex) //得到各个'#el' const event = key.slice(spaceIndex + 1) //得到各个'事件' const fn = eventFunctions[events[key]] //得到各个fn $(element).on(event, fn) //绑定事件 } }
核心思想就是去除重复的代码,看上去代码好像比简单的一个个绑定事件多了,但是等到再添加新事件或者事件多的时候这种方法就会很简洁;只需在events对象中添加即可,非常便捷。
模块化
随着前端的功能越来越多,越来越复杂,代码量页越来越庞大。
因此,将网页应用分为各个独立的模块单独开发,每个模块之间互不影响,可以使程序的结构更加清晰,方便维护。
现代浏览器已经原生支持了模块功能,使用export和import语句就可以实现。
在以前,实现一个应用需要引入html、css、js。有了模块化的思想,只需引入一个js就可以实现。
在main.js中引入各个模块的js,各个js再各自引用自己的css、创建自己的html。
我们还可以把这些模块用到的类,也封装成单独的模块,然后再将其引入到各个模块中。
如此,所有的模块都是独立的,互不影响,代码的层次结构会变得异常清晰。
引入js:
import 'css的地址 '
引入jQuery的新方法: 不添加script标签了,在终端使用命令引入, 在js中引入jquery
//1.先使用初始化 yarn init -y //2.安装jquery yarn add jquery //3.在js中引入jquery import $ from 'jquery'
类
在写MVC的时候,会发现在不同的项目中,相同的模块会有相同的属性,所以我们可以把这些属性封装在类的原型中,这时在每次创建MVC的时候,那些共有的属性就已经存在了,当发现一些属性的细节需要修改的时候还可以替换掉原来的属性。
class View { constructor(option) { super()// 调用EventBus#constructor() Object.assign(this, option)//options有什么我就把什么放到this上面 this.container = $(this.container) this.render(this.data)// view = render(data) this.autoBindEvens() this.on('m-updated', () => { this.render(this.data) }) } autoBindEvens() { for (let key in this.events) { const value = this[this.events[key]] const spaceIndex = key.indexOf(' ') const part1 = key.slice(0, spaceIndex) const part2 = key.slice(spaceIndex + 1) this.container.on(part1, part2, value) } } } //当使用这个类创建对象的后,所创建的那个对象就会本身自带这些属性
继承
最初创建了三个类Model,View和EventBus。这时我想让Model和View可以直接使用eventBus的属性,这时就可用到继承。
class View extends EventBus { constructor(option) { super()// 调用EventBus#constructor() Object.assign(this, option)//options有什么我就把什么放到this上面 this.container = $(this.container) this.render(this.data)// view = render(data) this.autoBindEvens() this.on('m-updated', () => { this.render(this.data) }) } autoBindEvens() { for (let key in this.events) { const value = this[this.events[key]] const spaceIndex = key.indexOf(' ') const part1 = key.slice(0, spaceIndex) const part2 = key.slice(spaceIndex + 1) this.container.on(part1, part2, value) } } } //这时通过View创建的对象就可直接使用EventBus里边的属性了例如.on .trigger
前端MVC,MVP,MVVM等设计模式简介