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()//初始化View
v.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 +=1
v.render(m.data.n)
})
v.el.on('click','#minus1',()=>{
m.data.n-=1
v.render(m.data.n)
})
v.el.on('click','#mul2',()=>{
m.data.n*=2
v.render(m.data.n)
})
v.el.on('click','#divide2',()=>{
m.data.n/=2
v.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} 导出事先定义的特性作为默认值
每一个模块中可定义多个命名导出;但是只允许有一个默认导出
,且具有层叠性
在导出多个值时,命名导出非常有用;在导入期间,必须使用相应对象的相同名称