灏天阁

同步模块模式

· Yin灏
/**
 * 模块化:将复杂的系统分解成高内聚、低耦合的模块,是系统开发变得可控、可维护、可扩展,提高模块的复用率。
 * 同步模块模式:请求发出后,无论模块是否存在,立即执行后续的逻辑,实现模块开发中的对象模块的立即引用。
 */

// 模块管理器与创建方法

// 定义模块管理器单体对象
/**
 * 首先定义一个模块管理器对象 F,然后为其创建一个模块定义方法 define
 */
var F = F || {};
/**
 * @param {*} str 模块路由
 * @param {*} fn  模块方法
 */
F.define = function (str, fn) {
  // 解析模块路由
  var parts = str.split("."),
    // old 当前模块的祖父模块,parent 当前模块父模块
    // 如果在闭包中,为了屏蔽对模块的直接访问,建议将模块添加给闭包内部私有变量
    old = (parent = this),
    // i 模块层级,len 模块层级长度
    i = (len = 0);

  // 如果第一个模式是模块管理器单体对象,则移除
  if (parts[0] === "F") {
    parts = parts.slice(1); // 删除数组第一个元素
  }
  // 屏蔽对 define 与 module 模块方法的重写
  if (parts[0] === "define" || parts[0] === "module") {
    return;
  }
  // 遍历路由模块并定义每层模块
  for (len = parts.length; i < len; i++) {
    // 如果父模块中不存在当前模块
    if (typeof parent[parts[i]] === "undefined") {
      // 声明当前模块
      parent[parts[i]] = {};
    }
    // 缓存下一层级的祖父模块
    old = parent;
    // 缓存下一层级父模块
    parent = parent[parts[i]];
  }
  // 如果给定模块方法则定义该模块方法
  if (fn) {
    // 此时 i 等于 parts.length , 故减一
    old[parts[--i]] = fn();
  }
  // 返回模块管理器单体对象
  return this;
};

/**
 * 创建模块
 * 创建 String 模块,对于 String 模块,要为我们提供 trim 方法
 */

// F.string 模块
F.define("string", function () {
  // 接口方法
  return {
    // 清楚字符串两边空白
    trim: function (str) {
      return str.replace(/^\s+|\s+$/g, "");
    },
  };
});
// 不允许如下直接使用
//console.log(F.string.trim(' 测试用例 ')); // '测试用例'

F.define("dom", function () {
  var $ = function (id) {
    $.dom = document.getElementById(id);
    return $;
  };
  $.html = function (html) {
    if (html) {
      this.dom.innerHTML = html;
      return this;
    } else {
      return this.dom.innerHTML;
    }
  };
  return $;
});

// 测试用例
console.log(F.dom("demo").html()); // 'demo'

/**
 * 对于模块的创建,我们也可以先声明后创建,如添加 addClass() 为元素添加 class 方法
 */

// 为模块 dom 添加 addClass 方法
F.define("dom.addClass");
F.dom.addClass = (function (type, fn) {
  return function (className) {
    // 如果不存在该类
    if (!~this.dom.className.indexOf(className)) {
      // 简单添加类
      this.dom.className += " " + className;
    }
  };
})();

// 测试用例
F.dom("demo").addClass("demo");

/**
 * 模块调用方法
 * 要使用方法,需要创建一个 ‘使用’ 模块方法 - module
 */

F.module = function () {
  // 将参数转化为数组
  var args = [].slice.call(arguments),
    // 获取回调执行函数
    fn = args.pop(),
    // 获取依赖模块,如果 args[0] 是数组,则依赖模块为 args[0],否则依赖模块为 arg
    parts = args[0] && args[0] instanceof Array ? args[0] : args,
    // 依赖模块列表
    modules = [],
    // 模块路由
    modIDs = "",
    // 依赖模块索引
    i = 0,
    // 依赖模块长度
    ilen = parts.length,
    // 父模块,模块路由层级索引,模块路由层级长度
    parent,
    j,
    jlen;

  // 遍历依赖模块
  while (i < ilen) {
    // 如果是模块路由
    if (typeof parts[i] === "string") {
      // 设置当前模块父对象(F)
      parent = this;
      // 解析模块路由,并屏蔽掉模块父对象
      modIDs = parts[i].replace(/^F\./, "").split(".");
      // 遍历模块路由层级
      for (j = 0, jlen = modIDs.length; j < jlen; j++) {
        // 重置父模块
        parent = parent[modIDs[j]] || false;
      }
      // 将模块添加到依赖模块列表中
      modules.push(parent);
    } else {
      // 如果是模块对象
      // 直接加入依赖模块列表中
      modules.push(parts[i]);
    }
    // 取下一个依赖模块
    i++;
  }
  // 执行回调执行函数
  fn.apply(null, modules);
};

// 调用模块

// 引用 dom 模块与 document 对象
F.module(["dom", document], function (dom, doc) {
  dom("demo").html("new add!");
  doc.body.style.background = "blue";
});

// 依赖引用 dom 模块, string.trim 方法
F.module("dom", "string.trim", function (dom, trim) {
  var html = dom("demo").html();
  var str = trim(html);
  console.log(str);
});

- Book Lists -