Treesaver 是浏览器大小尺寸敏感(size-sensitive)的,会就着当前的浏览器尺寸(browser size),选用不同的分栏表格(grid)做排版。
初始化
TreeSaver.js 框架的入口源代码在后面可以看到:https://github.com/Treesaver/treesaver/blob/master/src/init.js
这里的代码用到了Google开发的JS库:Closure Library,Closure Library的一个显著特点就是支持namespacing system(命名空间)。用过.Net和Java的对这个很熟悉。
这里init.js 文件的goog.provide('treesaver'); 就是表明以后如果你想用这个文件,你只需要引用名称空间:treesaver。goog.require('treesaver.boot');则是引用名称空间。
| Closure 代码 | .net等同代码 | java等同代码 |
| goog.provide('treesaver'); | namespace treesaver | package treesaver |
| goog.require('treesaver.boot'); | using treesaver.boot; | import treesaver.boot; |
初始化最核心的代码在:treesaver.ui.ArticleManager.load = function(initialHTML) {}
这个函数的调用堆栈如下,调用者在前面,被调用者在后面:
https://github.com/Treesaver/treesaver/blob/master/src/init.js
treesaver.boot.load = function() {}
treesaver.boot.loadProgress_ = function() {}
treesaver.core.load = function() {}
treesaver.ui.ArticleManager.load = function(initialHTML) {}
treesaver.ui.ArticleManager.load 传入的参数是我们页面的Html代码的Body部分。这个代码在显示上最核心的几段代码我加了中文注释。
/*** Initialize all content* @param {?string} initialHTML*/treesaver.ui.ArticleManager.load = function(initialHTML) {// Initialize statetreesaver.ui.ArticleManager.currentArticle = null;treesaver.ui.ArticleManager.currentPosition = null;treesaver.ui.ArticleManager.currentPageIndex = -1;treesaver.ui.ArticleManager.currentArticleIndex = null;treesaver.ui.ArticleManager.currentTransitionDirection = null;treesaver.ui.ArticleManager.currentPageWidth = null;// Data storetreesaver.ui.ArticleManager.articleOrder = [];treesaver.ui.ArticleManager.articleMap = {};treesaver.ui.ArticleManager.articles = {};treesaver.ui.ArticleManager.toc = [];/*** @private*/treesaver.ui.ArticleManager.grids_ = treesaver.ui.ArticleManager.getGrids_();if (!treesaver.ui.ArticleManager.grids_) {treesaver.debug.error('No grids');return false;}// Set up the loading & error pagestreesaver.ui.ArticleManager.initLoadingPage();treesaver.ui.ArticleManager.initErrorPage();treesaver.ui.ArticleManager.initialUrl = treesaver.network.stripHash(document.location.href);treesaver.ui.ArticleManager.initialHTML = initialHTML;// Set the display to the current article?if (initialHTML) {// ×××××× 开始构造显示 ××××××××××var initialArticle = new treesaver.ui.Article(treesaver.ui.ArticleManager.initialUrl,document.title,treesaver.ui.ArticleManager.grids_,initialHTML);if (!initialArticle.error) {// 缓存treesaver.ui.ArticleManager.articles[treesaver.ui.ArticleManager.initialUrl] = initialArticle;treesaver.ui.ArticleManager._setArticle(initialArticle, null, 0, true);}else {treesaver.debug.warn('Error in initial article');// Unload and show plain contenttreesaver.core.unload();}}else {treesaver.debug.warn('No initial article');// What to do here?}// Set up event handlers// *********** 文章分页,下一篇文章等的事件捆绑 **********treesaver.ui.ArticleManager.watchedEvents.forEach(function(evt) {treesaver.events.addListener(document, evt, treesaver.ui.ArticleManager.handleEvent);});window['onpopstate'] = treesaver.ui.ArticleManager.onPopState;// Download the table of contentstreesaver.ui.ArticleManager.generateTOC();return true;};
每次调整浏览器尺寸后
上面初始化代码中我们可以看到下面的代码:
// Set up event handlerstreesaver.ui.ArticleManager.watchedEvents.forEach(function(evt) {treesaver.events.addListener(document, evt, treesaver.ui.ArticleManager.handleEvent);});
treesaver.ui.ArticleManager.handleEvent 函数的实现如下:
/*** @param {Object} e*/treesaver.ui.ArticleManager.handleEvent = function(e) {if (e.type === treesaver.ui.Article.events.PAGINATIONPROGRESS) {// We have new pages to display// TODO// Fire eventtreesaver.events.fireEvent(document, treesaver.ui.ArticleManager.events.PAGESCHANGED);return;}if (e.type === treesaver.ui.Article.events.LOADED) {// TODO// If it's the current article, kick off pagination?// If it's the next, kick it off too?// Where does size come from?treesaver.events.fireEvent(document, treesaver.ui.ArticleManager.events.PAGESCHANGED);return;}if (e.type === treesaver.ui.Article.events.LOADFAILED &&e.article === treesaver.ui.ArticleManager.currentArticle) {// The current article failed to load, redirect to ittreesaver.ui.ArticleManager._redirectToArticle(treesaver.ui.ArticleManager.currentArticle);return;}};
TreeSaver的根控件就是 Chrome, 所以上面发出的事件会被下面代码拦截到:事件调度入口:
https://github.com/Treesaver/treesaver/blob/master/src/ui/chrome.js
这里的下面函数是所有事件的调度入口:
/*** Event dispatcher for all events* @param {Event} e*/treesaver.ui.Chrome.prototype['handleEvent'] = function(e) {switch (e.type) {// Both these events mean that the pages we are displaying// (or trying to display) may have changed. Make sure to// fetch them again// Article changed and TOC changed will affect nav indicatorscase treesaver.ui.ArticleManager.events.PAGESCHANGED:return this.selectPagesDelayed();case treesaver.ui.ArticleManager.events.TOCUPDATED:this.updateTOCDelayed();return this.selectPagesDelayed();case treesaver.ui.ArticleManager.events.ARTICLECHANGED:this.updateTOCActive(e);return this.updatePageURL(e);case 'mouseover':return this.mouseOver(e);case 'touchstart':return this.touchStart(e);case 'touchmove':return this.touchMove(e);case 'touchend':return this.touchEnd(e);case 'touchcancel':return this.touchCancel(e);case 'keydown':return this.keyDown(e);case 'click':return this.click(e);case 'mousewheel':case 'DOMMouseScroll':return this.mouseWheel(e);}};