做这个汉诺塔游戏的想法,来自于几个月前做百度IFE第一期的一个题目,题目要求在两个容器间实现子元素的相互拖拽效果。当时我就突发奇想:容器看成柱子,子元素看成盘子,再加一点限制底下盘子移动的判断和胜负的判断,不就和经典的汉诺塔游戏没什么两样吗?
和原题一样,做这游戏的难点就是拖放效果的实现,虽然用H5的原生拖放很容易实现,但是浏览器的兼容却不太好(IE10以下没有实现draggable属性,只有图片等一些特殊元素是可以拖动的)。于是当时还很naive的我用十分猥琐的鼠标事件套鼠标事件,艰难地实现了一个还能跑的程序,但是低水平的代码实在是太难看了(以至于我这次想重新实现一遍都得看好久)。
就没有优雅点的写法吗?当然有,《js高级程序设计》里就提供了一种高级的写法,也是利用鼠标事件,但在代码封装和接口设计上却比我高到不知道哪去了。具体实现可参考原书或这个,整个拖放效果被封装在一个单例对象里,只有enable和disable两个接口方法决定拖放的开启与否。接口很简单,但如果我们要在基本的拖动上再实现更加复杂的效果,就得依靠事件了。虽然我们没有办法对元素添加自定义事件,但是我们可以曲线救国,将自定义的拖动事件绑在单例对象上,然后利用鼠标事件间接触发相应的拖动事件即可。利用这段代码,我们就可以模仿出类似H5的原生拖动了。
而有了这一利器,我当然就想把原来写的乱七八糟的代码再重构一遍啦。感觉重构的过程刚开始就和吃剩饭一样,是比较痛苦的,但当你一步步用更优雅和高级的代码轻松实现原来你花半天才想出来的解决方案时,不仅会让你感叹你当初的天真,也会让你感叹原来写代码的体验可以如此美好、原来难题与痛苦不过是小case罢了。
ps.重构好的代码我放github上了,实现的效果可见其pages,一起玩玩呗,觉得好玩记得给star哈~