什么是MVC
MVC是一种软件设计模式
- M - model
模型层,是直接面向最终用户的"视图层"(View)。它是提供给用户的操作界面,是程序的外壳。
- V - view
视图层,是核心的"数据层"(Model),也就是程序需要操作的数据或信息。
- C - controller
控制层,是负责根据用户从"视图层"输入的指令,选取"数据层"中的数据,然后对其进行相应的操作,产生最终结果。
EventBus
eventBus是一个对象,它可以用来完成上述M、V、C对象间的通信。 例如,我们希望当M中的数据变化时,能够自动触发V的render,使变化后的数据即时渲染到界面上,如何做到呢? eventsBus提供了on、off、trigger等方法,用来处理事件。我们可以在M的data发生变动时,用trigger方法触发一个事件A(字符串):
m = {
data: {...},
methods: {
...
update(data){
修改m.data
eventBus.trigger(A)
}
}
}
复制代码然后,用on方法监听这个事件A,一旦事件A触发(即数据变化了),就调用V的render重新渲染视图:
eventBus.on(A, ()=>{
v.render(m.data)
})
如此,就实现了M和V之间的沟通,使得视图和数据保持同步。
表驱动编程
表驱动法就是一种编程模式(scheme)——从表里面查找信息而不使用逻辑语句(if 和case)。事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和直白。但随着逻辑链的越来越复杂,查表法也就愈发显得更具吸引力。
例如(使用jQ)
$('#div1).on('click', fn1)
$('#div2).on('click', fn2)
$('#div3).on('click', fn3)
$('#div4).on('click', fn4)
......
当我们给界面上多个元素绑定事件的时候,这样写起来就很麻烦。你可以说我我可以使用事件委托,但如果他们分布在不同的父元素中呢。这就麻烦了。
如果我们利用表驱动编程
events = {
'click #div1': 'fn1',
'click #div2': 'fn2',
'click #div3': 'fn3',
'click #div4': 'fn4',
},
fn1 () {}
fn2 () {)
fn3 () {}
fn4 () {}
autoBindEvents() {
for (let key in events) {
const value = events[key]
const spaceIndex = key.indexOf(' ')
const part1 = key.slice(0, spaceIndex)
const part2 = key.slice(spaceIndex + 1)
v.el.on(part1, part2, value)
}
这样虽然看起来代码反而变多了,但是如果我们将它放在一个对象里完整封装起来,他的内部是高度解耦的,当代码量越来越多的时候,后续的维护性,以及代码的可读性都是非常高的。
我是如何理解模块化的
模块化有利用代码解耦和复用,这也是软件工程一直在追求的东西。前端模块化的方案
- 闭包和封装函数
最典型的jQuery,就是利用这个思想。
- ES6 Modules 在ES6中,从语法层面就提供了模块化的功能。然而受限于浏览器的实现程度,如果想要在浏览器中运行,还是需要通过Babel等转译工具进行编译。ES6提供了import和export命令,分别对应模块的导入和导出功能。具体实例如下:
// demo-export.js 模块定义
var name = "scq000"
var sayHello = (name) => {
console.log("Hi," + name);
}
export {name, sayHello};
// demo-import.js 使用模块
import {sayHello} from "./demo-export";
sayHello("scq000");
- Webpack中的模块化方案 作为现代化的前端构建工具,Webpack还提供了丰富的功能能够使我们更加轻易地实现模块化。利用Wepack,你不仅可以将Javascript文件进行模块化,同时还能针对图片,css等静态资源进行模块化,时webpack还可以支持按需加载。
ule.exports = {
//...
output: {
library: 'librayName',
libraryTarget: 'umd', // 配置输出格式
filename: 'bundle.js'
}
};