• 单页WEB应用(三),Chat聊天模块


    Chat 聊天模块

    这个模块应该就是该书全篇的唯一一个模块吧,后面差点儿全部的篇章都环绕这个模块去实现的,只是就通过这一个模块的实现和上线,也能体现单页应用开发到公布上线的整个过程,毕竟后面的数据。通信。公布什么的都是通用的东西,应用其它部分全然能够參照这个‘聊天模块’去实现。跟着作者的思路走一遍,也能熟知个大概。

    先看下成型图吧,会不会有种非常老旧XP时代的感觉,囧!

    Chat聊天模块UI图

    chat 内容

    该聊天模块总体分下面几块:事实上都是跟着模版去实现的,差在详细实现上而已

    1. 配置;
    2. 事件处理。
    3. 初始化。

    涉及行为处理:
    1. 点击标题栏。显示或隐藏窗体。
    2. hash 值的变化触发聊天窗体的状态变化;

    重点在 通过 hash 值(锚)的变化来管理聊天窗体显示和隐藏。前面在shell里面实现过,这里主要拎出来作为一个单独模块来讲

    配置

    配置三大块:

    之前chat 模块是直接在shell模块中实现的,为了实现模块化,降低依赖,从而把该模块分离出来单独创建模块文件:spa.chat.js 和对应的样式和辅助文件等

    • configMap

      这里包括了chat模块的基本配置,和所用到的模块变量,来看下里面详细都有些啥

      var configMap = {
      
          // 模块的文档结构部分,通过动态载入到其父容器中
          main_html: '' 
              + '<div class="spa-chat">'
                  + '<div class="spa-chat-head">'
                      + '<div class="spa-chat-head-toggle">+</div>'
                      + '<div class="spa-chat-head-title">Chat</div>'
                  + '</div>'
                  + '<div class="spa-chat-closer">x</div>'
                  + '<div class="spa-chat-sizer">'
                      + '<div class="spa-chat-msgs"></div>'
                      + '<div class="spa-chat-box">'
                          + '<input type="text" />'
                          + '<div>send</div>'
                      + '</div>'
                  + '</div>'
              + '</div>',
      
      
          // 这个映射表,对应配置里面的变量,从对象名便可知,是用来
          // 保存配置是否可设置状态。true:表示该变量值能够改变,反之不能改动
          settable_map: { 
      
              slider_open_time    : true,
              slider_close_time   : true,
              slider_opened_em    : true,
              slider_closed_em    : true,
              slider_opened_title : true,
              slider_closed_title : true,
      
              chat_model      : true,
              people_model    : true,
              set_chat_anchor : true
          },
      
          // 窗体关闭和打开的动画时间,使用 $.animate 时使用的时间
          slider_open_time        : 250,
          slider_close_time       : 250,
          slider_opened_em        : 18,
          slider_closed_em        : 2,
      
          // 两个最小阀值用来防止页面被缩放的时候。聊天窗体同比例缩放导致变的太小而做出的限制
          // 这里单位是:em
          slider_opened_min_em    : 10,
          window_height_min_em    : 20,
      
          // 窗体打开和隐藏状态时。鼠标放在上面时显示的提示内容,通过元素的'title'属性实现
          slider_opened_title     : 'Click to close',
          slider_closed_title     : 'Click to open',
      
          // 两个数据模型,该书採用了数据库插件:taffyDb 来管理和模拟数据
          chat_model      : null,
          people_model    : null,
      
          // 此方法是聊天窗体显示和隐藏的关键
          // 核心模块shell 正是通过这个接口来管理聊天模块触发锚的变化从而
          // 让聊天模块具备前进后台历史等浏览器功能
          // 该方法指向shell模块中的 setChatAnchor 函数,
          // setChatAnchor 在 shell 中定义,与 'uriAnchor' 插件发生联系
          // 然后通过配置模块:configModule, 将该函数与`chat`模块发生联系,从而
          // 使 chat 改变 -> setChatAnchor -> shell 锚管理
          set_chat_anchor : null
      },

      通过 set_chat_anchor 改变聊天窗体状态变化路径图

      窗体点击事件触发hash变化

      通过图中就能明显的看出,chat 是怎样通过 shell 来实现状态更新。以及实现自身的前进后退历史等功能

    • stateMap

      相对于基本配置容器里面的配置,在执行过程中基本都不会有变化的值来说,stateMap 里面就是一些执行过程中,会由于用户行为而发生变化的一些状态值了

      突然发现人在不同的时间和不同的认知段会对同一个事物的理解和解释大有不同(废话么。谁不知道啊!

      var stateMap = {
      
          // 模块容器。不多说
          $container: null,
      
          // 位置值,表示模块窗体因用户行为而发生变化的状态值
          // 主要有:'closed','opened','hidden'
          position_type       : 'closed',
      
          // 单位转换, px/em,实际执行过程中会涉及到元素的位置设置。通过转换
          // 得到实际像素值,去设置
          px_per_em           : 0,
      
          // 下面三个就是针对三个不通状态时,窗体的位置了
          slider_hidden_px    : 0,
          slider_closed_px    : 0,
          slider_opened_px    : 0
      }

      针对 stateMap 里面的属性,有几个针对性的函数

      第一个就是 setPxSizes。由于页面都是通过 em 来设置大小的,因此在获取实际像素值的时候须要做个响应的转换

      /*
          这里面干了下面几件事:
      
          1. 获取 em -> px 的单位值,然后计算出当前文档窗体的总高度值:window_height_em
          2. 依据文档窗体决定模块窗体打开时的高度:opened_height_em
          3. 更新 stateMap 里面的窗体相关的状态值
          4. 最后确定聊天窗体内容体的详细高度
      
      */
      setPxSizes = function () {
      
          var
              px_per_em, opened_height_em, window_height_em;
      
          px_per_em = getEmSize( jqueryMap.$slider.get(0) );
      
          // 计算窗体高度:em
          window_height_em = Math.floor(
              ( $(window).height() / px_per_em ) + 0.5
          );
      
          // 依据范围值来决定窗体打开的高度
          opened_height_em 
              = window_height_em > configMap.window_height_min_em
              ? configMap.slider_opened_em
              : configMap.slider_opened_min_em;
      
          stateMap.px_per_em = px_per_em;
          stateMap.slider_closed_px = configMap.slider_closed_em * px_per_em;
          stateMap.slider_opened_px = opened_height_em * px_per_em;   
      
          jqueryMap.$sizer.css({
              height: ( opened_height_em - 2 ) * px_per_em
          });
      };
      
      // 这个函数,须要在初始化模块initModule中将模块载入到容器中之后,
      // 就须要执行,由于当中涉及的一些状态值须要在兴许执行操作过程中就要用到,
      // 比方:px_per_em, slider_closed_px,slider_opened_px 等等
      

      第二个函数就是:setSliderPosition,这个是真正改动聊天窗体显示隐藏状态的函数,里面通过$.animate 动画实现,而且是提供给 shell 模块。在 hash 值发生变化时触发了hashchange事件调用事件处理函数:onHashChange,里面依据详细的状态值去调用的,因此上面的状态走向图还不是非常准确。

      /*
      
          这里面的实现。主要依赖与:position_type,依据用户行为,去改变这个值。然后终于通过 hash 值的变化。传到这里,去改变窗体显示或隐藏
      
          里面涉及到的參数:
              height_px:动画的目标属性,窗体高度
              animate_time: 动画时间
              slider_opened_title:以及窗体改变后显示的 title 属性值
      
          最后通过动画结束后的回调:callback
      */
      
      setSliderPosition = function ( position_type, callback ) {
      
          var 
              height_px, animate_time, slider_title, toggle_text,
      
              setAttr;
      
          if ( stateMap.position_type === position_type ) {
              return true;
          }
      
          setAttr = function ( height, an_time, title, text ) {
      
              height_px       = height;
              animate_time    = an_time;
              slider_title    = title;
              toggle_text     = text;
          };
      
          switch ( position_type ) {
              case 'opened':
                  setAttr( 
                      stateMap.slider_opened_px,
                      configMap.slider_open_time,
                      configMap.slider_opened_title,
                      '='
                  );
              break;
      
              case 'hidden':
                  setAttr( 0, configMap.slider_open_time, '', '+' );
              break;
      
              case 'closed':
                  setAttr( 
                      stateMap.slider_closed_px,
                      configMap.slider_close_time,
                      configMap.slider_closed_title,
                      '+'
                  );
              break;
              default:
                  return false;
              break;
          }
      
          // 重置位置类型
          stateMap.position_type = '';
          jqueryMap.$slider.animate( 
              { height: height_px },
              animate_time,
              function () {
                  jqueryMap.$toggle.prop( 'title', slider_title );
                  jqueryMap.$toggle.text( toggle_text );
                  stateMap.position_type = position_type;
                  callback && callback( jqueryMap.$slider );
              }
          );
      
          return true;
      };

      上面的图改动之后加入 setSliderPosition 就比較完美了

      聊天窗体状态变化完整走向图

      最后为了应对窗体的 resize 事件。窗体须要做出对应的变化:handleResize

      // spa.chat.js
      
      handleResize = function () {
      
          if ( !jqueryMap.$slider ) { return false; }
      
          setPxSizes();
          if ( stateMap.position_type === 'opened' ) {
              jqueryMap.$slider.css({ height: stateMap.slider_opened_px });
          }
      
          return true;
      };
      
      // spa.shell.js 中应对 window 的 resize 事件
      
      onResize = function ( event ) {
      
          if ( stateMap.resize_idto ) { return true; }
      
          spa.chat.handleResize();
          stateMap.resize_idto = setTimeout(function () {
              stateMap.resize_idto = undefined;
          }, configMap.resize_interval);
      
          return true; 
      };
      

      值得一提的是应对 windowresize 事件方案採取的是针对每一个模块实现自己的应对方法。从而使模块能自己来决定怎样应对窗体的缩放应对方式

    • jqueryMap

      这里面的东西就不多记录了。都是些死的东西,缓存模块内元素的对象,方便jQuery使用,相同须要在该模块被追加到模块容器shell中之后才调用

      /*
          这里就不能直接用 $.html 了,而是使用 $.append 追加到模块容器 `shell` 模块当中
      */
      
      setJqueryMap = function () {
      
          var 
              $append_target = stateMap.$append_target,
              $slider = $append_target.find( '.spa-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]' ),
          };  
      };
      
      

    总结

    这篇主要介绍了该书对 chat 模块的处理,用这个演示样例来说明子模块怎样和模块管理器模块:shell相互作用。怎样组装子模块。怎样通过锚变化来管理子模块的状态变化,以及怎样应对 windowresize 事件的思想。另外还包括了怎样移除 chat 模块,当中涉及的 removeSlider 处理等。

    这里面须要注意的地方也没几处,主要感觉还是要弄清楚,模块的状态值和状态的变化怎样在子模块和 shell 模块之间是怎样传递以及起作用的,上面两张过程图更直观点。

    到此。模块的页面和组装基本完毕了,下一篇将会介绍该书是怎样实现数据模型,怎样让数据模型发生作用(数据管理插件:taffyDb)。

    完结,待续……!

  • 相关阅读:
    切片/修改
    代码块,-- 循环结构--字符串的格式化--字符串相关函数功能
    format 填充符号 与 格式化
    字符串的格式化format
    python字符串相关函数 *title *upper *lower *swapcase *len *count *find *index *starts with *endswith *isalpha *isdecimal *split *center *strip *replace
    双层循环经典小项目题
    while 小项目练习
    for循环 | range 对象
    关键字的使用 pass break continue
    python字符串的切片
  • 原文地址:https://www.cnblogs.com/clnchanpin/p/7340157.html
Copyright © 2020-2023  润新知