JavaScript制作Slide框架
概况
背景
又开始造一个新的轮子了,不过这次的起因比较简单,是想重新发明一个更好的Slide框架 —— EchoesWorks。如名字所言,我所需要的是一个回声
工坊,即将博客、Slide重新回放。
Showcase
GitHub代码: https://github.com/phodal/echoesworks
需求
当前我们有不同的方式可以记录我们的想法、博客、过程,如视频、音频、博客、幻灯片等等。
然而这些并非那么完美,让我们说说这些方式的一些缺陷吧。
视频。有很多技术视频从开始到结束,只有PPT,然后我们就为了这张PPT和声音下了几百M的视频。即使在今天网速很快,但是这并不代表我们可以在我们的手机上放下很多的视频。
音频。音频所受到的限制我想大家都很清楚。什么也不知道~~,什么也看不到,只能听。
博客。博客的主要缺点可能就是不够直接,有时会有点啰嗦。
幻灯片。一个好的PPT,也就意味着上面的内容是很少的。即如果没有人说的时候,就缺少真正有用的东西。
代码。我们真的需要在另外打开一个网址来看代码么?
于是,EchoesWorks
出现了,它可以支持下面的一些功能:
- 支持 Markdown
- Github代码显示
- 全屏背景图片
- 左/右侧图片支持
- 进度条
- 自动播放
- 字幕
- 分屏控制
步骤
Step 1: 基本的Slide功能
由于我是一个懒人,所以在实现基本的Slide功能时,我找到了一个名为bespoke
的迷你框架。原理大致和大家分享一下,在这个库里一共有下面几个函数:
- readURL() 读取URL来获取当前的页数,将跳转到相应的页数。
- activate(index, customData) 主要的函数,实际上就是切换className而已——将新的页面标记为’active’。
- writeURL(index) 切换slide的时候,更新URL的hash
- step(offset, customData) 计算页面
- on(eventName, callback) 事件监听函数
- fire(eventName, eventData) 事件触发函数
- createEventData (el, eventData) 创建事件的数据
大致的功能就如上所说的,相当简单。
Step 2: 解析Markdown
接着,我们就可以创建解析Markdown的功能了,遗憾的是这里的代码我也是用别人的——micromarkdown
,一个非常简单的Markdown解析器。
Step 3: 事件处理
在我们完成了基本的Slide功能后,我们就可以处理一些特殊的事件,如移动设备和键盘事件。在EW初始化时,我们可以会trigger一个名为ew:slide:init
的事件来告诉其他组件系统已经初始化了。这时在我们对应的事件处理函数中,我们就可以判断它是不是移动设备:
slides = document.getElementsByTagName('section');
syncSliderEventHandler();
if (slides && isTouchDevice && window.slide) {
touchDeviceHandler();
}
如果是移动设备,我们会额外的监听三个事件:
- touchstart
- touchend
- touchmove
如果是键盘输入的话,那么依据不同的按键做不同的处理:
document.addEventListener("keyup", function (event) {
var keyCode = event.keyCode;
if (keyCode === TAB || ( keyCode >= SPACE && keyCode <= PAGE_DOWN ) || (keyCode >= LEFT && keyCode <= DOWN)) {
switch (keyCode) {
case PAGE_UP:
case LEFT:
case UP:
window.slide.prev();
break;
case TAB:
case SPACE:
case PAGE_DOWN:
case RIGHT:
case DOWN:
window.slide.next();
break;
}
event.preventDefault();
}
});
如向上就展示下一张幻灯片,向下就展示下一张幻灯片。
Step 4: 解析字幕
在EchoesWorks中提供了一个很有趣的功能——类似于听歌时的歌词显示,并且可以自动播放和切换。它并没有用到什么特殊的技能,只是简单的对比时间,并且替换文字。
if (that.time < nextTime && words.length > 1) {
var length = words.length;
var currentTime = that.parser.parseTime(that.data.times)[currentSlide];
var time = nextTime - currentTime;
var average = time / length * 1000;
var i = 0;
document.querySelector('words').innerHTML = words[i].word;
timerWord = setInterval(function () {
i++;
if (i - 1 === length) {
clearInterval(timerWord);
} else {
document.querySelector('words').innerHTML = words[i].word;
}
}, average);
}
return timerWord;
}
Step 5: 进度条
一如既往的,我们的进度条,还是用别人已经写好的组件。这里我们用到的是nanobar。在Nanobar里,我们定义了一个go函数,在这个函数里来转换进度条:
Nanobar.prototype.go = function (p) {
this.bars[0].go(p);
if (p == 100) {
init.call(this);
}
};
在我们的slide文件里,再对其进行处理:
window.bar.go(100 * ( index + 1) / slides.length);
Step 6: 同步
在这里并没有什么特别高级的用法,只是简单的事件监听
function handler() {
window.slide.slide(parseInt(localStorage.getItem('echoesworks'), 10));
}
if (window.addEventListener) {
window.addEventListener("storage", handler, false);
} else {
// IE
window.attachEvent("onstorage", handler);
}
即,当监听到调用storage
的方法,就会跳转到相应的页面。
正常情况下,我们只用一个标签来展示我们的slide。当我们有另外一个标签的时候,我们就可以存储当前的slide。
localStorage.setItem('echoesworks', index);
这样就可以实现,在一个页面到下一页时,另外一个标签也会跳到下一页。