脚本模拟事件机制,基于MVP重写声文同步(without dojo lib)

资料:cab与mvp模式 http://www.agilelabs.cn/blogs/wind_tower/archive/2006/01/26/626.aspx
            Fowler MVP模式 http://www.martinfowler.com/eaaDev/ModelViewPresenter.html

   之前一篇文章中用dojo的事件订阅、发布机制实现了声文同步效果,相关信息可以参考 http://www.cnblogs.com/sharplife/archive/2006/08/22/483476.aspx  由于项目需要,改用了轻量级的客户端库prototype,抛弃dojo的事件机制,因此重写声文同步的实现,顺面利用昨天晚上时间总结一下,我下面的介绍的实现中用到些prototype库中元素,但其实可以很方便的改成完全native的js实现。
   
   对于实现中涉及的传输数据的json模型可以参见之前的文章,这次实现采用mvp模式,说的明了些与mvc模式的不同处就是完全解除了model、view之间的耦合,也即model和view可以相互不知道对方的存在,用presenter控制器实现view、model的交互、更新(和之前的实现功能上是一致肯定会有许多相似处)。

类图

   以上类图其实是之前在之前用c#在winform实现时留下的,图中只显示了各接口的关键方法、属性及事件定义(当然在下面的js实现中我就没定义相应的接口了,因为脚本中接口概念很模糊),IAudioUtil适用于包装播放控件的接口,这样在不同的播放控件间切换就方便了,其关键事件有PositionChanged和StatusChanged,在之前的c#实现中PositionChanged是用用一个后台线程单独模拟的(这样在播放状态变化的时候就需要适时的调整后台线程的状态,如Suspend、Abort等,在涉及与view交互时还要考虑 非主线程对UI的更新),下面js的实现中,我们用prototype中的PeriodicalExecuter模拟PositionChanged事件的实现(因为我们的控件未提供、或是提供的PositionChanged事件不符合要求),相对来讲更方便,当然完全可以用js的setTimeout或setInterval native实现。

   下面介绍一个正常播放时各对象的交互,播放控件的PositionChanged事件主要由IPModel中的每个子IsentenceModel订阅,当检查到当前播放的position位于自身(一个sentence)的开始、结束时间之间,则触发自身的ItemInvoke事件,而各子model的此事件被IPresenter订阅,继而做更新IPModel、更新IPView的操作,并最终触发由Ipresenter所拥有的唯一的事件displaySentence,由其他订阅者订阅以做个性化的显示,交互时序如下:

正常播放交互图

   另一个典型的交互便是由用户单击、或者双击view(我们的具体实现中体现为web页面的容器元素),首先view会更新自身的状态(更新当前sentence),因为这没必要经由控制器通知view再去更新自身,然后触发view本身所拥有的click、dbclick事件(这两个事件是在view类中模拟出来的,并非web页面的单、双击事件,不过view中各sentence所处容器元素span的单、双击会分别触发此两事件),之后订阅此二事件的Presnter控制器会进行设置播放器信息(如暂停,当前播放位置)、更新model的操作,之后同上一个交互过程,触发displaySentence事件,如果是双击除了同样执行上述操作外会还有最后一个播放操作(因为双击事件会首先触发单击事件,所以我们的实现就简单了,同样也是值得注意的地方)。

用户单双击时序图

主要实现代码如下:
播放控件对象
   注意AudioUtil类中positionChanged事件的实现,如上面所提在c#中需控制后台线程的状态,我们同样要适当控制PeriodicalExecuter的执行(如在pause、stop等状态),另外由于positionChanged事件会被各子model订阅,所以我们将其订阅者的处理方法放在js对象中,在触发时用protype的$H结合each遍历并执行(传输对象参数e)所有处理方法。

Model对象
   ParagraphModel主要完成分析从服务端获取的json串、计算各sentence的开始、结束时间、构造出各子SentenceModel(自身完成对播放器positionChanged事件的订阅)

Presenter对象
   ParagraphPresenter拥有model及view的实例,订阅了view的click及dbclick事件,同时订阅了model中各子model的itemInvoke事件,完成model、view之间通讯。

View对象

   ParagraphView的首要任务是根据传入的sentence数据及html元素将model展现在web页面上,其中完成了各sentence在web页面上的单双击触发ParagraphView的click、dbclick事件(将各自本身sentence对象做参数传入)的操作。

   demo效果截图就不放了,实现一般的声文同步(如歌词秀应该不成问题),总结一下,本次实现并没有过多考虑js在ie上的memory leak问题,本实现用了n多js closure,想是循环引用是免不了的了,优化应该有许多可以做吧,就先说到这了(没做较大段落文本的测试)。
   [回应下之前的文章,现在js的开发、调试环境越来越好了,而RIA的解决方案也增多了]

你可能感兴趣的:(dojo)