设计模式知识连载(45)---同步模块模式:

<body>


<h3>设计模式知识连载(45)---同步模块模式:</h3>
<div>
    <p>
        模块化:将复杂的系统分解成高内聚、低耦合的模块,使系统开发变得可控、可维护、可拓展,提高模块的复用率
    </p>
    <p>
        请求发出后,无论模块是否存在,立即执行后续的逻辑,实现模块开发中对模块的立即引用。
    </p>
</div>


<hr>

<div id = 'test'>   test   </div>


<script type="text/javascript">



    /**
    *   案例一:排队开发,方式一:初始
    */
    // /* A工程师,获取数据并创建导航模块(沿用A框架)*/
    // // 导航数据
    // var data = null ;
    // // 获取导航逻辑
    // var dom = A('#nav') ;
    // // 创建导航逻辑
    // var createNav = function() {
    //  // A 工程师完成导航创建逻辑
    // };
    // /****** C工程师加入,为导航添加引导图片 ******/
    // var lis = A('li', dom) ;
    // for(var i = 0; i < data.length; i++) {
    //  if(data[i].hasGuide) {
    //      $(lis[i]).addClass('has-guide') ;
    //  }
    // }
    // /*********************************************/
    // /****** B工程师加入,完成对导航添加事件需求 ******/
    // // 在导航容器中获取每条导航容器
    // var li = A('', dom) ;
    // li.on('mouseover', function() {
    //  // 显示下拉狂逻辑
    // }).on('mouseout', function() {
    //  // 隐藏下拉框逻辑
    // }) ;
    // /*************************************************/
    // // 获取导航数据
    // A.ajax('data/nav', function(res) {
    //  if(res.errNo == 0 ) {
    //      // 保存数据
    //      data = res.data ;
    //      // 创建的导航模块
    //      createNav() ;
    //  }
    // }) ;


    /**
    *   案例一:排队开发,方式二:进阶
    */
    // 定义模块管理器单体对象
    var F = F || {} ;
    /**
    *   定义模块方法(理论上,模块方法应放在闭包中实现,可以隐蔽内部信息。【此处忽略此步骤】)
    *   @param str 模块路由
    *   @param fn 模块方法
    **/
    F.define = function(str, fn) {
        // 解析模块路由
        var parts = str.split('.') ;
        // old当前模块的祖父模块,parent当前模块父模块
        // 如果在闭包中,为了屏蔽对模块直接访问,建议将模块添加给闭包内部私有变量
        var old = parent = this ;
        // i:模块层级;len:模块层级长度
        var i = len = 0 ;

        // 如果第一个模式是模块管理器单体对象,则移除
        if(parts[0] === 'F') {
            // slice() 方法可从已有的数组中返回选定的元素。
            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 ;
    }

    // 创建模块
    // F.string模块
    F.define('string', function() {
        // 接口方法
        return {
            // 清除字符串两边空白
            trim : function(str) {
                return str.replace(/^\s+|\s+$/g, '') ;
            }
        }
    }) ;

    // 测试用例:
    /*
        注意:在真正的模块开发中,是不允许这样直接调用的,有两点原因,技术上,模块通常保存在闭包内部的私有变量里,而不会保存在F上,因此是获取不到的,而这里简化了闭包,也为测试方便,因此直接引用。其次,类似如下调用是不符合模块化开发规范的。
    */
    var testStr = '   测试用例    1234' ;
    console.log('testStr.length:', testStr.length) ;
    var str1 = F.string.trim(testStr) ;
    console.log('str1.length:', str1.length) ;

    /*******************************************************************/
    /*
    对于模块的回调函数,也可以以构造函数的形式返回接口,比如创建DOM模块,其中包括dom()获取元素方法、html()获取或者设置元素innerHTML内容方法等
    */
    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 $ ;
    }) ;
    // 测试用例:
    var text = F.dom('test').html() ;
    console.log('text:', text) ;

    /*******************************************************************/
    /*
    对于模块的创建,也可以先声明后创建,比如添加addClass()为元素添加class方法。
    */
    // 为dom模块添加addClass方法
    // 注意:此种添加模式之所以可行,是因为将模块添加到F对象上,模块化开发中只允许上面的添加方式
    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('test').addClass('my-class') ;


    /*******************************************************************/
    // 模块调用方法---创建一个“使用”模块方法:module
    F.module = function() {
        // 将参数转化为数组
        var args = [].slice.call(arguments) ;
        // 获取回调执行函数
        var fn = args.pop() ;
        // 获取依赖模块,如果args[0]是数组,则依赖模块args[0]。否则依赖模块arg
        var parts = args[0] && args[0] instanceof Array ? args[0] : args ;
        // 依赖模块列表
        var modules = [] ;
        // 模块路由
        var modIDs = '' ;
        // 依赖模块索引
        var i = 0 ;
        // 依赖模块长度
        var ilen = parts.length ;
        // 父模块,模块路由层级索引,模块路由层级长度
        var 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模块设置元素内容
    //  dom('test').html('new add!') ;
    //  // 通过document设置body元素背景色
    //  doc.body.style.background = 'red' ;
    // }) ;


    // 依赖引用dom模块,string.trim方法
    F.module('dom', 'string.trim', function(dom, trim) {
        // 测试元素:<div id = 'test'>   test   </div>
        // 获取元素内容
        var html = dom('test').html() ;
        // 去除字符串两边空白符
        var str = trim(html) ;
        console.log('*' + html + '*', '*' + str + '*') ;
    }) ;
</script>    

</body>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值