MVC概念

M 就是 model, 即数据模型,负责数据相关的任务,包括对数据的增删改查
V 就是view, 即视图层,即用户能看得到的界面
C 就是 Controller,控制器,负责监听用户事件,然后调用 M 和 V 更新数据和视图

1.1 Model 数据模型

数据相关的整合进 M

  1. //示例
  2. let Model={
  3. data:{数据源},
  4. create:{增加数据},
  5. delete:{删除数据},
  6. update(data){
  7. Object.assign(m.data,data)//用新数据替换旧数据
  8. eventBus.trigger('m:update')//eventBus触发'm:update'信息,通知View刷新界面
  9. },
  10. get:{获取数据}
  11. }

1.2 View 视图层

视图相关放到 V

  1. //示例
  2. let View={
  3. el:要刷新的元素,
  4. html'要显示在页面上的刷新内容'
  5. init(){
  6. v.el:初始化需要刷新的元素
  7. },
  8. render(){
  9. 刷新页面
  10. }
  11. }

1.3 Controller 控制器

业务逻辑放到 C

  1. let Controller={
  2. init(){
  3. v.init()//初始化View
  4. v.render()//第一次渲染页面
  5. c.autoBindEvents()//自动的事件绑定
  6. eventBus.on('m:update',()=>{v.render()}//当enentsBus触发'm:update'是View刷新
  7. },
  8. events:{事件以哈希表的方式记录存储},
  9. //例如:
  10. events: {
  11. 'click #add1': 'add',
  12. 'click #minus1': 'minus',
  13. 'click #mul2': 'mul',
  14. 'click #divide2': 'div',
  15. },
  16. add() {
  17. m.update({n: m.data.n + 1})
  18. },
  19. minus() {
  20. m.update({n: m.data.n - 1})
  21. },
  22. mul() {
  23. m.update({n: m.data.n * 2})
  24. },
  25. div() {
  26. m.update({n: m.data.n / 2})
  27. },
  28. method(){
  29. data=新数据
  30. m.update(data) // controller 通知 model去更新数据
  31. },
  32. autoBindEvents(){
  33. for (let key in c.events) { // 遍历events表,然后自动绑定事件
  34. const value = c[c.events[key]]
  35. const spaceIndex = key.indexOf(' ')
  36. const part1 = key.slice(0, spaceIndex) // 拿到 'click'
  37. const part2 = key.slice(spaceIndex + 1) // 拿到'#add1'
  38. v.el.on(part1, part2, value)
  39. }
  40. }

EventBus

EventBus 常用三个 API 分别是:trigger()、on()、off()
on 用于监听事件,trigger 用于触发事件,off用于移除事件

  1. const m = {
  2. ....
  3. update(data) {
  4. Object.assign(m.data, data)
  5. eventBus.trigger('m:updated') // 通知一下view层,我已经更新了数据,view该开始工作了
  6. localStorage.setItem('n', m.data.n)
  7. },
  8. ....
  9. }

controller中会用 on 监听事件, 然后通知 view 模型去重新渲染页面

  1. const c = {
  2. init(container) {
  3. v.init(container)
  4. v.render(m.data.n) // view = render(data)
  5. c.autoBindEvents()
  6. eventBus.on('m:updated', () => { // controller会用 on 监听事件,
  7. //然后通知 view 模型去重新渲染页面
  8. console.log('here')
  9. v.render(m.data.n)
  10. })
  11. },
  12. ...
  13. }

表驱动编程

表驱动法就是一种编程模式(scheme)——从表里面查找信息而不使用逻辑语句(if 和 case)
解决if else面对多种情况的情形,以表的形式进行获取数据,通过下标索引来查

  1. bindEvents(){
  2. v.el.on('click','#add1',()=>{
  3. m.data.n +=1
  4. v.render(m.data.n)
  5. })
  6. v.el.on('click','#minus1',()=>{
  7. m.data.n-=1
  8. v.render(m.data.n)
  9. })
  10. v.el.on('click','#mul2',()=>{
  11. m.data.n*=2
  12. v.render(m.data.n)
  13. })
  14. v.el.on('click','#divide2',()=>{
  15. m.data.n/=2
  16. v.render(m.data.n)
  17. })
  18. }

表驱动编程改写为:

  1. events:{ //用哈希表存下按钮和按钮对应的操作
  2. 'click #aa1':'add',
  3. 'click #minus1':'minus',
  4. 'click #mul2':'mul',
  5. 'click #divide2':'div'
  6. },
  7. add(){
  8. m.update( data: {n:m.data.n +1})
  9. },
  10. minus(){
  11. m.update( data:{n:m.data.n -1})
  12. },
  13. mul(){
  14. m.update( data: {n:m.data.n *2})
  15. },
  16. div(){
  17. m.update(data: {n:m.data.n /2})
  18. }

事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和直白,但随着逻辑链的越来越复杂,查表法也就愈发显得更具吸引力。

关于模块化

模块化概念:
将繁杂冗长的代码按照一定的规则规范分成多个块(可以是面向对象的方式)或者文件,然后再进行组合实现想要的功能和结果。
模块化好处:

  1. 降低代码的耦合度,还可以封装细节,向外暴露接口
  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 导出方式:

  1. 命名导出(每个模块包含任意数量)

export {xxx,yyy} 导出事先定义的特性
export let xxx = {} 导出单个特性,可以是var、let、const、function、class

  1. 默认导出(每个模块包含一个)

export default x 将一个变量默认导出给外部使用
export {xxx as default} 导出事先定义的特性作为默认值
每一个模块中可定义多个命名导出;但是只允许有一个默认导出 ,且具有层叠性
在导出多个值时,命名导出非常有用;在导入期间,必须使用相应对象的相同名称