事件驱动的理解

写JS不用事件驱动跟咸鱼有什么区别

事件驱动是个好东西

曾经接连做过好几个H5音乐播放器,一个用JQuery另外两个原生方式写的。但无论怎么样都让我觉得,不了解一样东西就不要去使用[1]

就比如,ended事件会告诉你播放已经停止;play事件会告诉你播放开始[2]pause事件会告诉你播放已经暂停[3]

第一次的时候,我一共摸索出了这三种,并做出了个还可以的播放器[4]。但是问题也很多,比如进度条的问题,当时并不知道有progress事件这个好东西,而且也没有使用好 play/pause/end三个事件,所以导致bug丛生……

第二次是 simplePlayer[5]moebaka的一个播放器,这个播放器可以说是我对事件驱动理解的一个里程碑。不仅仅是因为进度条的问题[6]

第三次是 myPlayer,目前仅仅自家用的一个播放器,平时还偶尔拿出来玩玩。这个可以说是simplePlayer[7]的简化版。嗯,要说不同的地方就在于支持移动端[8]和更节约内存(

由此想到的一个编程模型

最近,我写了个MarkdownViewer[9],给了我很大的启发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// sMDV 0.1a frame.js
var editorEle = $('#editor')[0];
var articleEle = $('#article')[0];
var viewerEle = $('#viewer')[0];
var frameEle = $('#frame')[0];
var mEvent = new function (){
var my = this;
this.viewButton = function (str){
var articleContent = (typeof str==='string' ? str : editorEle.value);
//代码高亮支持
var converter = new Markdown.Converter();
Markdown.Extra.init(converter, {highlighter: "prettify"});
//Markdown 转HTML
articleEle.innerHTML = converter.makeHtml(articleContent);
articleEle.onload = prettyPrint();
viewerEle.style.top = '0%';
viewerEle.style.opacity = '1';
frameEle.style.opacity = '0';
frameEle.style.marginTop = '150px';
};
this.closeViewer = function (){
viewerEle.style.top = '100%';
viewerEle.style.opacity = '0';
frameEle.style.opacity = '1';
frameEle.style.marginTop = '0px';
};
this.about = function (){
$.get('about.md', function (d){
my.viewButton(d);
});
};
this.how2use = function (){
$.get('how2use.md', function (d){
if (confirm('你确定要删除当前编辑的文本吗?')){
editorEle.value = d;
}
});
};
this.save = function (){
downloadFile('sMDV.md', editorEle.value);
};
};
//$('#editor')[0].value = "# simple MDV";
viewerEle.style.top = '100%';
viewerEle.style.opacity = '0';
$('#view_button')[0].onclick = mEvent.viewButton;
$('#view_close')[0].onclick = mEvent.closeViewer;
$('#about_button')[0].onclick = mEvent.about;
$('#how2use_button')[0].onclick = mEvent.how2use;
$('#save_button')[0].onclick = mEvent.save;
/* thanks http://www.jb51.net/article/47723.htm */
function downloadFile(fileName, content){
var aLink = document.createElement('a');
var blob = new Blob([content]);
var evt = document.createEvent("HTMLEvents");
evt.initEvent("click", false, false);//initEvent 不加后两个参数在FF下会报错, 感谢 Barret Lee 的反馈
aLink.download = fileName;
aLink.href = URL.createObjectURL(blob);
aLink.dispatchEvent(evt);
}

仔细一看,可能就会发现我将所有的事件都放在了 mEvent 对象里。mEvent里放着各种处理事件的函数,函数里面就包括着处理动画的代码[10],然后各种……

这个应该就是典型的事件驱动的编程方式吧?这样的好处也有,那就是逻辑很清晰,知道点了什么后就会怎么怎么样,然后又会怎么怎么样……各种orz


  1. 当然,这是极端点的说法 ↩︎

  2. 我更认同 Audio.play() 后执行的事件,这样更准确 ↩︎

  3. 也是 Audio.pause()后执行的事件,如果播放过程中出现不可抗力(诸如断开网络连接,歌曲出错),并不会执行这个事件,出错的貌似是 error 事件 ↩︎

  4. 只有播放、暂停、下一曲、上一曲、随机播放、单曲循环、全曲循环的功能,别的遇到了瓶颈就没写下去了 ↩︎

  5. 目前因为工作瘫痪,我也无心维护,所以坑了 ↩︎

  6. 动画效果完全的事件驱动,而不需要再由自己去控制…… ↩︎

  7. 少了个列表功能 ↩︎

  8. 支持度有限 ↩︎

  9. 仅仅是壳…… ↩︎

  10. 应该说是配合着 CSS Transition 的动画吧(苦笑) ↩︎