MVC概念
M 就是 model, 即数据模型,负责数据相关的任务,包括对数据的增删改查
V 就是view, 即视图层,即用户能看得到的界面
C 就是 Controller,控制器,负责监听用户事件,然后调用 M 和 V 更新数据和视图
1.1 Model 数据模型
数据相关的整合进 M
//示例let Model={data:{数据源},create:{增加数据},delete:{删除数据},update(data){Object.assign(m.data,data)//用新数据替换旧数据eventBus.trigger('m:update')//eventBus触发'm:update'信息,通知View刷新界面},get:{获取数据}}
1.2 View 视图层
视图相关放到 V
//示例let View={el:要刷新的元素,html:'要显示在页面上的刷新内容'init(){v.el:初始化需要刷新的元素},render(){刷新页面}}
1.3 Controller 控制器
业务逻辑放到 C
let Controller={init(){v.init()//初始化Viewv.render()//第一次渲染页面c.autoBindEvents()//自动的事件绑定eventBus.on('m:update',()=>{v.render()}//当enentsBus触发'm:update'是View刷新},events:{事件以哈希表的方式记录存储},//例如:events: {'click #add1': 'add','click #minus1': 'minus','click #mul2': 'mul','click #divide2': 'div',},add() {m.update({n: m.data.n + 1})},minus() {m.update({n: m.data.n - 1})},mul() {m.update({n: m.data.n * 2})},div() {m.update({n: m.data.n / 2})},method(){data=新数据m.update(data) // controller 通知 model去更新数据},autoBindEvents(){for (let key in c.events) { // 遍历events表,然后自动绑定事件const value = c[c.events[key]]const spaceIndex = key.indexOf(' ')const part1 = key.slice(0, spaceIndex) // 拿到 'click'const part2 = key.slice(spaceIndex + 1) // 拿到'#add1'v.el.on(part1, part2, value)}}
EventBus
EventBus 常用三个 API 分别是:trigger()、on()、off()
on 用于监听事件,trigger 用于触发事件,off用于移除事件
const m = {....update(data) {Object.assign(m.data, data)eventBus.trigger('m:updated') // 通知一下view层,我已经更新了数据,view该开始工作了localStorage.setItem('n', m.data.n)},....}
controller中会用 on 监听事件, 然后通知 view 模型去重新渲染页面
const c = {init(container) {v.init(container)v.render(m.data.n) // view = render(data)c.autoBindEvents()eventBus.on('m:updated', () => { // controller会用 on 监听事件,//然后通知 view 模型去重新渲染页面console.log('here')v.render(m.data.n)})},...}
表驱动编程
表驱动法就是一种编程模式(scheme)——从表里面查找信息而不使用逻辑语句(if 和 case)
解决if else面对多种情况的情形,以表的形式进行获取数据,通过下标索引来查
bindEvents(){v.el.on('click','#add1',()=>{m.data.n +=1v.render(m.data.n)})v.el.on('click','#minus1',()=>{m.data.n-=1v.render(m.data.n)})v.el.on('click','#mul2',()=>{m.data.n*=2v.render(m.data.n)})v.el.on('click','#divide2',()=>{m.data.n/=2v.render(m.data.n)})}
表驱动编程改写为:
events:{ //用哈希表存下按钮和按钮对应的操作'click #aa1':'add','click #minus1':'minus','click #mul2':'mul','click #divide2':'div'},add(){m.update( data: {n:m.data.n +1})},minus(){m.update( data:{n:m.data.n -1})},mul(){m.update( data: {n:m.data.n *2})},div(){m.update(data: {n:m.data.n /2})}
事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和直白,但随着逻辑链的越来越复杂,查表法也就愈发显得更具吸引力。
关于模块化
模块化概念:
将繁杂冗长的代码按照一定的规则规范分成多个块(可以是面向对象的方式)或者文件,然后再进行组合实现想要的功能和结果。
模块化好处:
- 降低代码的耦合度,还可以封装细节,向外暴露接口
- 每个模块之间相对独立,增加代码的复用性和后期可维护性
ES6的语法里引入了Import和export就是用来实现模块化的
export和import用法
export导出
在创建JavaScript模块时,export 语句用于从模块中导出实时绑定的函数、对象或原始值,
以便其他程序可以通过 import 语句使用它们。
被导出的绑定值依然可以在本地进行修改。
在使用import进行导入时,这些绑定值只能被导入模块所读取,
但在export导出模块中对这些绑定值进行修改,所修改的值也会实时地更新。
import导入
import x from ‘./xxx.js’ 引用另一个模块导出的默认变量
import {x} from ‘./xxx.js’ 引用另一个模块导出的名为 x 的变量
存在两种 exports 导出方式:
- 命名导出(每个模块包含任意数量)
export {xxx,yyy} 导出事先定义的特性
export let xxx = {} 导出单个特性,可以是var、let、const、function、class
- 默认导出(每个模块包含一个)
export default x 将一个变量默认导出给外部使用
export {xxx as default} 导出事先定义的特性作为默认值
每一个模块中可定义多个命名导出;但是只允许有一个默认导出
,且具有层叠性
在导出多个值时,命名导出非常有用;在导入期间,必须使用相应对象的相同名称
