MVC
- M - Model : 数据模型 负责操作数据
const m = {
data: {
n: parseInt(localStorage.getItem("n"))
}
}
- V - View : 视图 负责UI界面
const v = {
el: null,
html: `
<div>
<div id="content">{{n}}</div>
<div id="buttons">
<button id="add">加2</button>
<button id="minus">减2</button>
<button id="multiply">乘2</button>
<button id="division">除2</button>
</div>
</div>
`,
init(el) {
v.el = $(el)
},
render(n) {
if (v.el.children.length !== 0) v.el.empty()
$(v.html.replace('{{n}}', n)).appendTo(v.el)
}
}
- C - Controller 控制器 负责其他
const c = {
events: {
' click #add': 'add',
' click #minus': 'minus',
' click #multiply': 'multiply',
' click #division': 'division'
},
add() {
console.log('here');
m.update({n:m.data.n+2})
},
minus() {
m.update({n:m.data.n-2})
},
multiply() {
m.update({n:m.data.n*2})
},
division() {
m.update({n:m.data.n/2})
},
autoBindEvents() {
for (let key in c.events) {
const value = c[c.events[key]]
const spaceIndex = key.indexOf(' ')
const part1 = key.slice(0, spaceIndex)
const part2 = key.slice(spaceIndex + 1)
v.el.on(part1, part2, value)
}
}
}
模块化
- 模块就是实现特定功能的一组方法。
- 各模块各司其职,互不影响,标准化的接口
- 当有该模块功能的需求时直接调用
- 每个文件的代码都会小而清晰
- 代码复用
最小知识原则
- 引入一个模块需要引入 js
- 你需要知道的知识越少越好
不把 app1.js 写死,实现随便传一个可用参数都能实现他的功能。
// 在 app1.js 里把 c 暴露出去
export default c
// 在 main.js 导入 x ,x 即为 app1.js 里的c
import x from "./app1.js";
// 实现在 app1.js 外部使用其功能
x.init("#app1")
问题
页面一开始可能是空白的,可加菊花、骨架、占位内容等优化
以不变应万变
- 每个模块都使用 m + v + c 架构
- 不用考虑类似的需求如何做,自己套用即可
表驱动编程
- 当出现大量类似但不重复的代码
- 提取重要数据,将其做成哈希表
对一个个按钮绑定事件,除了按钮与对应的触发事件不同,其他都是一样的。使用表驱动编程优化代码。
events:{
'#btnPause': 'pause',
'#btnSlow': 'slow',
'#btnNormal': 'normal',
'#btnFast': 'fast'
},
bindEvents:()=>{
for(let key in player.events){
if(player.events.hasOwnProperty(key)){
const value = player.events[key]
document.querySelector(key).onclick = player[value]
}
}
},
eventBus
当 C 中的按钮监听事件触发时,都要将 data 修改,重新渲染页面,即调用 V 中的 render(m.data.n),因此每个按钮监听事件都要显示的加上 v.render(m.data.n),如何优化?
引用eventBus
- 在 M 中写一个 update()方法,将 eventBus 的事件触发 xxx 添加进去
update(data) {
Object.assign(m.data, data)
//事件触发
eventBus.trigger('xxx')
}
- 在 C 中的按钮事件监听中执行 update() 方法,相当于触发事件 xxx
- 在 V 中写 eventBus 的事件监听 xxx 方法,监听到 xxx 事件的触发就执行render
eventBus.on('xxx',()=>{
v.render(m.data.n)
})
因此,eventBus实现了对象间的通信,也可看出 M 层与 V 层的关系紧密,实现数据与页面同步进行。
view = render(data)
- 操作 DOM 对象渲染页面的机制是 js 从页面获取数据,DOM 处理数据后渲染页面
- 事实上,比起操作 DOM ,直接 render 简单多了
- js 通过自身获取了数据,直接 render 渲染页面,数据修改的同时 render 渲染页面。
弊端
- render 粗犷的渲染比起 DOM 操作浪费性能
- 虚拟 DOM 可以解决
- 它能让 render 只更新该更新的地方
对象原型与公用属性 ----建立中间层,隔绝细节
- 既然所有的模块都是 MVC 架构 ,那么对 MVC 进行改写
- 创建一个类,将 M 里边的属性与方法分别写入类的自身属性与方法中
- M 是类的实例并传入对应的参数
- 不同模块中的 M都可成为该类的实例,使用类的方法
- 其它类似
继承类
- 既然所有的模块都需要 EventBus 来实现对象间的通信
- 创建一个 EventBus 类,写好触发事件、监听事件等方法
- 让创建的类都去继承 EventBus 类
- 实例都可拥有 EventBus 的方法,就无需重写多次