Web前端学习笔记——模块化开发

目录

概述

什么是模块化开发

非模块化开发的问题

为什么使用模块化开发

实现模块化的推演

step-01 全局函数

step-02 封装对象

step-03 划分私有空间

step-04 模块的扩展与维护

step-05 第三方依赖管理

实现规范

CommonJS规范

AMD规范

CMD规范

•服务器端规范

•浏览器端规范

CMD实现-SeaJS

AMD实现-RequireJS

SeaJS和RequireJS对比

实现Seajs

使用步骤

定义一个模块

使用一个模块

导出成员的方式

异步加载模块

使用第三方依赖(jQuery)

Seajs配置

使用案例

RequireJS


概述

什么是模块化开发

  • 将软件产品看作为一系列功能模块的组合
  • 通过特定的方式实现软件所需模块的划分、管理、加载

非模块化开发的问题

命名冲突

添加命名空间YUI 、EXTJS---可以从一定程度上解决命名冲突,但是增加了开发人员记忆冗长api的难度。

文件依赖

团队变大后,维护大量的文件依赖关系非常困难,公共模块的维护、升级很不方便。

为什么使用模块化开发

  • https://github.com/seajs/seajs/issues/547
  • 协同
  • 代码复用
  • 解决问题
    • 大量的文件引入
    • 命名冲突
    • 文件依赖
    • 存在
    • 顺序

实现模块化的推演

step-01 全局函数





  
  全局函数的形式
  



  
  
  
  
  
  



step-02 封装对象





  
  封装函数的方式
  



  
  
  
  
  
  



step-03 划分私有空间





  
  封装函数的方式
  



  
  
  
  
  
  



step-04 模块的扩展与维护





  
  封装函数的方式
  



  
  
  
  
  
  



step-05 第三方依赖管理





  
  封装函数的方式
  
  



  
  
  
  
  
  



在什么场景下使用模块化开发 业务复杂 重用逻辑非常多 扩展性要求较高


实现规范

CommonJS规范

AMD规范

CMD规范

•服务器端规范

CommonJS---nodejs

•浏览器端规范

AMD---RequireJS 国外相对流行

CMD---SeaJS 国内相对流行

CMD实现-SeaJS

 SeaJS---阿里巴巴前端架构师玉伯

             js文件的依赖管理、异步加载,方便前端的模块化开发。

             官方网站:http://seajs.org/

AMD实现-RequireJS

             RequireJS-James Burke AMD规范的创始人

            与SeaJS 基本实现类似的功能

            中文官网:http://www.requirejs.cn/

SeaJS和RequireJS对比

  • 对于依赖的模块,AMD是提前执行,CMD是延后执行
  • CMD推崇依赖就近,AMD推崇依赖前置
  • AMD的API默认是一个当多个用,CMD的API严格区分,推崇职责单一

实现Seajs

使用步骤

  1. 在页面中引入sea.js文件
  2. 定义一个主模块文件,比如:main.js
  3. 在主模块文件中通过define的方式定义一个模块,并导出公共成员
  4. 在页面的行内脚本中通过seajs.use('path',fn)的方式使用模块
  5. 回调函数的参数传过来的就是模块中导出的成员对象

定义一个模块

  • define

javascript define(function(require, exports, module) { exports.add = function(a, b) { return a + b; }; });

使用一个模块

  • seajs.use
    • 一般用于入口模块
    • 一般只会使用一次
  • require
    • 模块与模块之间





  
  Seajs体验
  
  



  
  
  
  
  



 



// 定义一个模块,遵循Seajs的写法
define(function(require, exports, module) {
  // 此处是模块的私有空间
  // 定义模块的私有成员
  // 载入01-convertor模块
  var convertor = require('./01-convertor.js');

  function add(a, b) {
    return convertor.convertToNumber(a) + convertor.convertToNumber(b);
  }

  function subtract(a, b) {
    return convertor.convertToNumber(a) - convertor.convertToNumber(b);
  }

  function multiply(a, b) {
    return convertor.convertToNumber(a) * convertor.convertToNumber(b);
  }

  function divide(a, b) {
    return convertor.convertToNumber(a) / convertor.convertToNumber(b);
  }
  // 暴露模块的公共成员
  exports.add = add;
  exports.subtract = subtract;
  exports.multiply = multiply;
  exports.divide = divide;
});

 


/**
 * 转换模块,导出成员:convertToNumber
 */
define(function(require, exports, module) {
  // 公开一些转换逻辑
  exports.convertToNumber = function(input) {
    return parseFloat(input);
  }
});

导出成员的方式

  • module.exports
  • exports.xxx
  • return
  • 三种方式的优先级





  
  Seajs体验
  
  



  
  
  
  
  





// 定义一个模块,遵循Seajs的写法
define(function(require, exports, module) {

  // function add(a, b) {
  //   return parseFloat(a) + parseFloat(b);
  // }

  // function subtract(a, b) {
  //   return parseFloat(a) - parseFloat(b);
  // }

  // function multiply(a, b) {
  //   return parseFloat(a) * parseFloat(b);
  // }

  // function divide(a, b) {
  //   return parseFloat(a) / parseFloat(b);
  // }
  // // 暴露模块的公共成员
  // exports.add = add;
  // exports.subtract = subtract;
  // exports.multiply = multiply;
  // exports.divide = divide;

  // console.log(module.exports === exports);
  //
  // function Person(name, age, gender) {
  //   this.name = name;
  //   this.age = age;
  //   this.gender = gender;
  // }

  // Person.prototype.sayHi = function() {
  //   console.log('hi! I\'m a Coder, my name is ' + this.name);
  // };

  // // exports.Person = Person;
  // module.exports = Person;
  // 最终导出的以 module.exports
  // module.exports = { name: 'world' };
  // // 此时module.exports 指向的是一个新的地址
  // exports.name = 'hello';
  // // exports是module.exports的快捷方式,指向的任然是原本的地址

  // module.exports优先级第二
  module.exports = { name: 'hello' };
  console.log(module);
  // return 的优先级最高
  return { name: 'world' };
});

 

异步加载模块

  • 默认require的效果是同步的,会阻塞代码的执行,造成界面卡顿
  • require.async();
require.async('path',function(module) {

});





  
  Seajs体验
  
  



  
  
  
  
  



 



define(function(require, exports, module) {
  // console.log('module1 ---- start');
  // // require 必须执行完成过后(./module2.js加载完成)才可以拿到返回值
  // var module2 = require('./03-module2.js'); // 阻塞代码执行
  // // JS中的阻塞会有卡顿的情况出现
  // console.log('module1 ---- end');
  //
  console.log('module1 ---- start');
  require.async('./03-module2.js', function(module2) {

  }); // 此处不会阻塞代码执行

  console.log('module1 ---- end');
});

 



define(function() {
  console.log('module2 exec');
});

使用第三方依赖(jQuery)

  • 由于CMD是国产货,jquery默认不支持
  • 改造

javascript // 适配CMD if (typeof define === "function" && !define.amd) { // 当前有define函数,并且不是AMD的情况 // jquery在新版本中如果使用AMD或CMD方式,不会去往全局挂载jquery对象 define(function() { return jQuery.noConflict(true); }); }






  
  Seajs使用第三方依赖
  
  






 



'use strict';

define(function(require, exports, module) {
  // 想用jquery怎么办
  var $ = require('./jquery.js');
  console.log($);
  $(document.body).css('backgroundColor', 'red');
});

Seajs配置

  • 配置
  • seajs.config
    • base
    • alias





  
  
  






 



'use strict';
define(function(require, exports, module) {
  console.log(11111);
});

使用案例

  • Tab标签页





  
  使用模块化的方式定义一个分页组件
  
  
  



  

       

      
      
      define(function(require, exports, module) {
        var Pagination = require('./modules/pagination.js');
        var pager = new Pagination(1, 20, 7);
        pager.render('.pagination');
        pager.render('.pagination1');
      });
      

       

      
      
      define(function(require, exports, module) {
      // format = 'http://www.baidu.com/page/@/'
        function Pagination(current, total, show, format) {
          this.current = current;
          this.total = total;
          this.show = show;
          // 1. 根据显示数量算出正常情况当前页的左右各有几个
          var region = Math.floor(show / 2);
          // 2. 计算出当前界面上的起始值
          var begin = current - region; // 可能小于 1
          begin = begin < 1 ? 1 : begin;
          var end = begin + show; // end必须小于total
          if (end > total) {
            end = total + 1;
            begin = end - show;
            begin = begin < 1 ? 1 : begin;
          }
          this.begin = begin;
          this.end = end;
        };
      
        /**
         * 渲染当前这个组件到界面上
         */
        Pagination.prototype.render = function(containers) {
          // 获取分页展示容器
          // p.render('.pgfds');
          if (typeof containers === 'string') {
            containers = document.querySelectorAll(containers);
          }
          if (containers.length === undefined) {
            // dom对象
            containers = [containers];
          }
          for (var c = 0; c < containers.length; c++) {
            var container = containers[c];
            // 先append上一页
            var prevElement = document.createElement('li');
            prevElement.innerHTML = '';
            if (this.current == 1) {
              prevElement.classList.add('disabled');
            }
            container.appendChild(prevElement);
            for (var i = this.begin; i < this.end; i++) {
              var liElement = document.createElement('li');
              liElement.innerHTML = '' + i + '';
              if (i == this.current) {
                // 此时是当前页
                liElement.classList.add('active');
              }
              container.appendChild(liElement);
            }
            var nextElement = document.createElement('li');
            nextElement.innerHTML = '';
            if (this.current == this.total) {
              nextElement.classList.add('disabled');
            }
            container.appendChild(nextElement);
          }
        };
      
        module.exports = Pagination;
      });
      

      RequireJS

      你可能感兴趣的:(Web前端,WEB前端开发)