核心模块 Shell
该模块是整个单页应用的核心模块,也可以说是顶级模块,用来组装和管理其他子模块的模块,其实该书中的所有模块都有模版,作者将其放到了附录里面,东西也不多主要就这几块:
- 模块配置
- jquery 缓存组件数据
- 模块初始化
- 和一些其他的功能方法等
例如:Shell
模块就包含以下内容
模块配置
模块基本配置对象:
configMap
例如:
shell
模块的基本配置var configMap = { /* 这个配置,是每个模块都需要的配置,主要针对模块的页面 字符串形式,保存了模块的结构代码,通过jQuery.html方法 添加到其父级元素下(即包含该模块的容器里面,相对shell模块,该容器即 id='spa' 的 div) 比如下面的内容即shell模块所包含的组件 */ main_html: '' + '<div id="spa">' + '<div class="spa-shell-head">' + '<div class="spa-shell-head-logo"></div>' + '<div class="spa-shell-head-acct"></div>' + '<div class="spa-shell-head-search"></div>' + '</div>' + '<div class="spa-shell-main">' + '<div class="spa-shell-main-nav"></div>' + '<div class="spa-shell-main-content"></div>' + '</div>' + '<div class="spa-shell-foot"></div>' + '<div class="spa-shell-modal"></div>' + '</div>' }, stateMap = {}, jqueryMap = {}
模块状态配置:
stateMap
该对象保存了模块内几乎所有可变数据的变化及状态值,从而统一管理模块数据,和数据的变化,说白了 其实就是跟模块相关的变量,状态值的一个容器。
下面是
shell
模块的状态配置var stateMap = { $container : null, anchor_map : {} } /* 这里东西不多,主要保存了两个属性 $container: 几乎每个模块都存在,即包含该模块的组件 */
再看后面一个子模块:
chat
聊天模块的状态值var stateMap = { $container: null, position_type : 'closed', px_per_em : 0, slider_hidden_px : 0, slider_closed_px : 0, slider_opened_px : 0 } /* 这个模块的东西就稍微多点,包含 聊天模块位置类型:'closed', 'opened', 'hidden',说明这个值会在这三个之间发生变化,并且由 stateMap 容器来保管维护 以及下面的其他属性或状态值等等 */
jQuery
容器:jqueryMap
第三个就是
jQuery
的容器了,刚接触时还不太明白用处,现在大概明白了,其实就是缓存的作用,在这里会将jQuery
所用的的数据,元素等先缓存起来,不至于用的时候再去重新读取元素,这可能会牺牲点开始的加载速度,不过这点影响估计可以忽略不记了(毕竟一个模块的元素还是有限的,也不会太多,并且针对单个元素的获取速度应该还是很快的),这对后面通过jQuery
去访问元素将是一大便捷和快速,同时也能很明了的从这里看出模块大概所涉及的元素,或其他一些信息。var jqueryMap = {};
由于涉及到DOM元素对象,加上模块又是动态加载到DOM中的,所以针对这个容器,有个对应的设置函数:
setJqueryMap
,一般会在模块调用$.html
之后调用,去初始化该容器shell
模块setJqueryMap = function () { var $container = stateMap.$container; jqueryMap = { $container: $container }; };
chat
子模块setJqueryMap = function () { var $append_target = stateMap.$append_target, $slider = $append_target.find( '.spa-chat' ); // chat模块相对来说保存的元素对象比较全点,这里就缓存了聊天 // 模块的所有元素,而不至于在后续使用过程中再去获取,这种方式更加高效,相对后续的操作会更快点 jqueryMap = { $slider : $slider, $head : $slider.find( '.spa-chat-head' ), $toggle : $slider.find( '.spa-chat-head-toggle' ), $title : $slider.find( '.spa-chat-head-title' ), $sizer : $slider.find( '.spa-chat-sizer' ), $msgs : $slider.find( '.spa-chat-msgs' ), $box : $slider.find( '.spa-chat-box' ), $input : $slider.find( '.spa-chat-box input[type=text]' ), }; };
shell
模块函数,及模块处理控制
这个模块,主要起到组装子模块作用,实际上shell
模块本身是不需要多少控制代码,最多会包含一些全局性的控制或辅助部分,比如:URL的 Hash 变化和控制,作者使用了个锚控制 jquery 插件:uriAnchor
,大概的功能和代码了解了点,有些地方还是不太清晰,后面会针对这个插件研究下
其实大概的原理不是很复杂,主要涉及的其实就是,针对每个模块去维护自己的状态值,然后 uriAnchor
插件实时的去更新状态值,其中有个比较容易忽略的地方,也是其中一个核心的地方,就是 anchor_schema_map
这个锚映射表中的值,必须是 true
后面才会起到作用,因为这个纠结了一整天,坑死了。
具体的细节还不是非常清晰,这篇之后会去研究下,然后自己实现下,这个插件针对单页应用,或者需要自己手动实现浏览器上的‘前进’,‘后退’,‘刷新’等功能还是很有帮助的。
组装子模块
比如:当下实现的
chat
聊天模块,先配置后初始化,配置的主要有chat
模块点击指定地方之后触发点击事件,然后调用set_chat_anchor
去改变当前 URL 的hash
值,然后核心shell
模块会监控url
的hash
值的变化事件,做出相应的行为// spa.chat.js // chat_model, people_model 属于模块私有的数据模型 spa.chat.configModule({ set_chat_anchor : setChatAnchor, chat_model : spa.model.chat, people_model : spa.model.people }); // 执行的初始化里面,会将当前模块的 html 代码追加到参数中的容器后面,加上 // spa.chat.css 模块的样式,便能完整在容器中显示出来 spa.chat.initModule( jqueryMap.$container );
总结
模版
该书中的单页应用模版,不管是核心总管
shell
或者 子模块都能套用该模版,主要内容就文头说的三大块,数据块,控制逻辑,和初始化,总体布局还是比较清晰的。而主要实现方式,其实还是立即执行匿名函数方式:
// spa.module.template.js spa.module = (function () { var configMap = { main_html: '' + '<div>' + 'Module Html' + '</div>', settable_map: { color_name: true }, color_name: 'blue' }, stateMap = { $container: null }, jqueryMap = {}, setJqueryMap, configModule, initModule; /* ----------------------- BEGIN UTILITY METHODS ----------------------- */ setJqueryMap = function () { var $container = stateMap.$container; jqueryMap = { $container: $container }; }; /* ----------------------- END UTILITY METHODS ----------------------- */ /* ----------------------- BEGIN DOM METHODS ----------------------- */ /* ----------------------- END DOM METHODS ----------------------- */ /* ----------------------- BEGIN EVENT METHODS ----------------------- */ /* ----------------------- END EVENT METHODS ----------------------- */ /* ----------------------- BEGIN PUBLIC METHODS ----------------------- */ /** * 配置允许访问的键值 * * @param {Object} input_map 允许设置的属性的键值对 * * configMap.settable_map 中保存了允许设置的属性 * * @return {[type]} [description] */ configModule = function ( input_map ) { spa.util.setConfigMap({ input_map : input_map, settable_map : configMap.settable_map, config_map : configMap }); return true; }; initModule = function ( $container ) { stateMap.$container = $container; setJqueryMap(); return true; }; /* ----------------------- END PUBLIC METHODS ----------------------- */ return { configModule : configModule, initModule : initModule }; });
心得
目前学习完第四章,代码也基本手敲了一遍,经过这日志记录,思路也重新缕了一遍,这书的模块的实现对于我这种初学者来学还是值得学习的,遇到的问题和不解最多的还是那个
uriAnchor
插件的实现,虽然原理不是很复杂,还是需要去琢磨下,争取彻底明白原理,自己能实现。该书目前阅读进度来说值得学习借鉴的地方
- 数据的统一性:通过一个统一的配置容器来管理每个模块自己的数据;
- 缓存的重要性:通过缓存来减少操作过程中重复获取 DOM 元素;
- 模块依赖性:尽量减少模块之间的依赖程度;