[TOC]
## 概況
### 背景
又開始造一個新的輪子了,不過這次的起因比較簡單,是想重新發明一個更好的Slide框架 —— EchoesWorks。如名字所言,我所需要的是一個`回聲`工坊,即將博客、Slide重新回放。
### Showcase

EchoesWorks
GitHub代碼:?[https://github.com/phodal/echoesworks](https://github.com/phodal/echoesworks)
### 需求
當前我們有不同的方式可以記錄我們的想法、博客、過程,如視頻、音頻、博客、幻燈片等等。
然而這些并非那么完美,讓我們說說這些方式的一些缺陷吧。
1. 視頻。有很多技術視頻從開始到結束,只有PPT,然后我們就為了這張PPT和聲音下了幾百M的視頻。即使在今天網速很快,但是這并不代表我們可以在我們的手機上放下很多的視頻。
2. 音頻。音頻所受到的限制我想大家都很清楚。什么也不知道~~,什么也看不到,只能聽。
3. 博客。博客的主要缺點可能就是不夠直接,有時會有點啰嗦。
4. 幻燈片。一個好的PPT,也就意味著上面的內容是很少的。即如果沒有人說的時候,就缺少真正有用的東西。
5. 代碼。我們真的需要在另外打開一個網址來看代碼么?
于是,`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);
~~~
這樣就可以實現,在一個頁面到下一頁時,另外一個標簽也會跳到下一頁。
### 練習建議