javascript模塊化(二)--RequireJS初探

前言:在慕課網上跟着視頻《側邊工具欄開發》作了一遍,用到了jquery操做DOM,其中,用requirejs管理模塊依賴,而後自定義了兩個模塊它們都依賴jquery,而且其中一個自定義模塊依賴另外一個,因此要暴露出接口。看完視頻初步認識了一下requirejs,以及模塊化開發的概念,在此作一下總結。感謝慕課網上的老師。javascript

使用模塊化開發的好處:css

  1. 有效的防止命名衝突html

  2. 聲明不一樣的js文件之間的依賴java

  3. 可讓咱們寫出模塊化的代碼,便於複用jquery

1.需求與目標

這個視頻《側邊工具欄開發》的需求很簡單,就是作一個側邊工具條,windows

  1. 固定定位在頁面的某個位置,數組

  2. 在沒有把頁面向下滾動時,顯示三個按鈕,瀏覽器

  3. 當頁面向下滾動必定距離以後,第四個按鈕出現。微信

  4. 點擊這個按鈕,頁面會回到頂部。app

  5. 鼠標hover到每一個按鈕上都有一些相應的動畫(CSS3完成這裏不寫)

圖片描述圖片描述

2.HTML結構

<div class="toolbar">
            <!--第一個微信按鈕-->
            <a href="javascript:;" class="toolbar-item toolbar-item-weixin">
                <span class="toolbar-layer"></span>
            </a>
    
            <!--第二個意見反饋按鈕-->
            <a href="javascript:;" class="toolbar-item toolbar-feedback"></a>
    
            <!--第三個app下載按鈕-->
            <a href="javascript:;" class="toolbar-item toolbar-item-app">
                <span class="toolbar-layer"></span>
            </a>
    
            <!--第四個回到頂部按鈕-->
            <a id="backTop" href="javascript:;" class="toolbar-item toolbar-item-top"></a>
        </div>

一些說明:

  1. 爲了讓頁面顯示滾動條,須要在這個上述代碼下面加不少行<p></p>標籤以便撐開頁面顯示滾動條。

  2. CSS部分視頻中老師講了三種方法,而且用到了SASS,感興趣的同窗能夠去看一下,這裏再也不贅述。

3.requirejs入門

(1)項目目錄結構

其中jquery-3.1.0.js和require.js是在各自官網下載的資源文件。main.js是自定義的入口文件。
圖片描述

(2)加載初始化requirejs

在未引入模塊化編寫代碼之前引入js文件是在<body>標籤以前寫多個<script>標籤,根據js文件加載的順序,添加js文件。如今根據requirejs的異步加載的特性,能夠設定一個主入口文件,只用一個<script>實現其他js文件的加載。

  1. 首先是引入requirejs:在HTML文件的<body>標籤的以前添加script標籤,

  2. 而後引入requirejs文件,而後用data-main這個屬性來引入入口文件。(當用requirejs引用文件時,能夠省略js文件的js後綴名,因此此處引入的就是項目目錄中的main.js
    以下:

<script src="js/require.js" data-main="js/main"></script>

(3)requirejs的經常使用方法

  1. requirejs.config爲模塊指定別名,方便模塊的引入),在入口文件中定義
    如這個demo要引入屢次jquery-3.1.0.js,可是這個名字很長因此能夠在入口文件main.js中爲它定義一個別名,以下:

//爲jquery模塊定義別名
    requirejs.config({
        paths:{
            jquery:'jquery-3.1.0.js'
        }
    });
  1. requirejs()方法(將寫好的模塊進行引入
    requirejs()接收兩個參數,第一個參數是一個數組,寫入要引入的模塊的名字。第二個參數是一個回調函數,須要傳遞一個參數,來代替前面所引入的模塊。如:引入jquery模塊

requirejs(['jquery'],function($){
        //寫一段代碼驗證jquery是否被正確引入
        //將body背景顏色變爲紅色
        $('body').css('background-color','red');
    });
  1. define()(利用它定義編寫模塊,而後在相應的地方進行引入。)
    define()接收三個參數,第一個參數是爲本模塊命名的值,能夠不寫,第二個參數表示須要引入的模塊,第三個參數是各依賴項成功加載後所運行的函數,傳入的參數與各個依賴項造成對應的關係。

define(
        moduleName,  //可選,若是此參數不寫,則默認使用本模塊所在文件的文件名
        dependencies,    //一個數組,此數組包含着此文件所需的各個依賴項目,這個數組中各項對應的是所依賴文件相對於requirejs庫所造成的相對路徑文件名。
        function(parameters){  
            //各依賴項成功加載後所運行的函數
            //傳入的參數與dependencies數組中的各個依賴項造成對應關係
        }
    );

(4)demo的基本功能實現

如今先對demo中的基本功能進行實現:

目前的目錄結構以下:
圖片描述

  1. 首先在HTML中初始化requirejs:在</body>標籤以前:
    <script src="js/require.js" data-main="js/main"></script>

  2. 在入口文件main.js中實現基本功能

//1.首先爲jquery模塊定義別名
    requirejs.config({
        paths: {
            jquery: 'jquery-3.1.0'
        }
    });
        
    //2.而後用requirejs()方法引入jquery模塊實現demo中需求
    requirejs(['jquery'],function($){
    
        //爲id值爲backTop的第四個按鈕添加點擊回到頂部事件,當點擊時執行move函數回到頂部
        $('#backTop').on('click',move);
        
        //監聽一下windows對象的滾動事件,
        //每次滾動都執行函數checkPosition肯定一下位置,是否到達設定的臨界點,以顯示和隱藏第四個按鈕
        $(window).on('scroll',function(){
            checkPosition($(window).height());
        });
        
        //解決bug:在刷新頁面時也出現第四個按鈕,即頁面加載時就檢查一下滾動位置
        checkPosition($(window).height());

//------------------------------分割線------------------------------------------
        //move函數的具體實現,加動畫效果
        function move(){
            $('html, body').animate({
                scrollTop:0
            },800);
        }
        //go函數能夠當即移動到頂部
        function go(){
            $('html, body').scrollTop(0);
        }

        //checkPosition函數的具體實現
        function checkPosition(pos){
            if($(window).scrollTop() > pos){
                $('#backTop').fadeIn();
            }else{
                $('#backTop').fadeOut();
            }
        }
    });

分割線以上是執行的代碼,分割線如下是寫的被調用的函數。

(5)將功能抽象成模塊

上述代碼雖然實現了功能,可是存在如下問題:

  1. move和go函數都是到達頂部的功能,實現的功能很類似,做用若是想在其它地方使用這個功能,就要再進行代碼的複製,不方便功能的複用。因此應該將功能抽象成模塊。

  2. 實現功能的功能單一:兩個函數都是到達頂部,這樣即使抽象成模塊也會受到很大的限制,因此能夠進一步將問題抽象成移動滾動條到指定位置。

第一步:建立一個新模塊,用scrollto.js表示,目前這個demo的目錄結構如圖:
圖片描述

第二步:將功能抽象成模塊,寫入scrollto.js

//1.先定義這個模塊,由於要用到jquery,因此還要引入jquery
    define(['jquery'],function($){
        //定義構造函數
        function ScrollTo(opts){
            this.opts = $.extend({},ScrollTo.DEFAULTS,opts);   //實現傳參覆蓋
            this.$el = $('html, body');
        }
    
        //原型添加方法
        ScrollTo.prototype.move = function (){
            var opts = this.opts;
            this.$el.animate({
                scrollTop:opts.dest
            },opts.speed);
        };
        ScrollTo.prototype.go = function(){
            this.$el.scrollTop(opts.dest);
        };
    
        //定義默認的參數
        ScrollTo.DEFAULTS = {
            dest:0,
            speed:800
        };
        
        //定義接口
        return {
            ScrollTo:ScrollTo
        };
        
    });

代碼詳解:

  1. 傳遞的參數爲一個對象,用opts表示

  2. 用戶沒有傳遞參數時,使用默認的參數,默認參數直接寫在ScrollTo構造函數上,至關於造成一個靜態屬性,而後經過jquery的extend()方法進行原型的擴展

  3. 實現用戶傳遞參數用之,不傳遞參數用默認值。jquery的extend()方法

  4. 在原型上添加move和go方法

第三步:在入口文件main.js中引入這個scrollto.js的模塊

requirejs(['jquery','scrollto'], function($,scrollto){
    
        //爲了使用scrollto模塊,須要實例化一下
        var scroll = new scrollto.ScrollTo({
            dest:0,
            speed:2000
        });
        //點擊回到頂部按鈕回到指定位置功能
        $('#backTop').on('click', $.proxy(scroll.move, scroll));
    
    });

上述代碼中有一點須要注意:

  1. 在第6行中,若是添加點擊按鈕回到指定位置事件時,這麼寫:
    $('#backTop').on('click', scroll.move);

  2. 此時瀏覽器控制檯會報錯:Uncaught TypeError: Cannot read property 'ScrollTo' of undefined

  3. 分析緣由是由於,在main.js中調用scrollto.js模塊中在ScrollTo.prototype.move原型方法move時,main.js中this指的是ScrollTo的實例,即scrollto,而在語句$('#backTop').on('click', scroll.move);中,這個this指代的是id爲backTop的這個按鈕。

  4. 解決辦法:用jquery提供的方法,直接將this指向scroll對象。
    $('#backTop').on('click', $.proxy(scroll.move, scroll))

第四步:一個bug
這時基本功能雖然實現了,點擊底部那個按鈕,傳入設定的返回位置和返回的速度,頁面能夠再次返回頂部指定位置,可是目前還存在一個bug:在點擊底部按鈕回到頂部指定位置時,假如連續屢次點擊這個按鈕,則頁面回到頂部後就沒法再次向下滾動頁面。

bug分析:

  1. 假如執行的函數如上面第三步中代碼,速度設置成較慢的速度2000,那麼在返回頂部指定位置時能夠屢次點擊這個按鈕,

  2. 這樣每次點擊按鈕事件都要調用move方法執行裏面的動畫,點擊多少次,這個動畫就要執行多少次。

  3. 所以在頁面返回頂部後,再次滾動頁面向下會當即執行返回頂部動畫,因此在執行完點擊次數的動畫以前,用戶都沒法向下滾動。(而且很是耗性能)

解決辦法,在滾動條正在運動或者已經到達目的地,就不該該執行動畫。添加判斷。
因此scrollto.js的代碼能夠改爲以下:

define(['jquery'],function($){
        //定義構造函數
        function ScrollTo(opts){
            this.opts = $.extend({},ScrollTo.DEFAULTS,opts);   //實現傳參覆蓋
            this.$el = $('html, body');
        }
    
        //原型添加方法
        ScrollTo.prototype.move = function (){
            var opts = this.opts;
            if ($(window).scrollTop() != opts.dest){  //判斷是否到達指定位置
                if(!this.$el.is(':animated')){    //判斷是否在運動
                    this.$el.animate({
                        scrollTop:opts.dest
                    },opts.speed);
                }
            }
        };
        ScrollTo.prototype.go = function(){
            var dest = this.opts.dest;
            if($(window).scrollTop() != dest){
                this.$el.scrollTop(dest);
            }
        };
    
        //定義默認的參數
        ScrollTo.DEFAULTS = {
            dest:0,
            speed:800
        };
        
        //定義接口
        return {
            ScrollTo:ScrollTo
        };
              
    });

(6)將返回頂部總體抽象成模塊

咱們把返回的功能函數move和go都抽象在了scrollto.js模塊中,如今還能夠直接把整個返回頂部的功能(包括滾動必定距離後隱藏的按鈕出現,和點擊按鈕以後回到頂部指定位置)
而後在入口文件中只須要引入這個模塊(取名叫backtop.js),這個back.js須要依賴上面定義的scrollto.js模塊。

因此目前的項目目錄以下圖:
圖片描述

第一步:如今來寫backtop.js模塊

define(['jquery', 'scrollto'], function($, scrollto){
        //執行函數部分
        function BackTop(el, opts){
            this.opts = $.extend({}, BackTop.DEFAULTS, opts);
            this.$el = $(el);   //el是節點
            this.scroll = new scrollto.ScrollTo({
                dest: 0,
                speed: this.opts.speed     
            });
            
            this._checkPosition();   //加載時就檢查位置,解決bug
            
            if(this.opts.mode == 'move'){  //是move才執行move函數,其餘執行go
                this.$el.on('click', $.proxy(this._move, this));
            }else{
                this.$el.on('click', $.proxy(this._go, this));
            }
            
            $(window).on('scroll', $.proxy(this._checkPOsition, this));
 
        }
    
        //定義默認屬性部分
        BackTop.DEFAULTS = {
            mode: 'move',
            pos: $(window).height(),
            speed: 800
        };
    
    
        //定義功能函數部分
        BackTop.prototype._move = function(){
            this.scroll.move();
        };
    
        BackTop.prototype._go = function(){
            this.scroll.go();
        };
    
        BackTop.prototype._checkPosition = function(){
            if($(window).scrollTop() > this.opts.pos){
                this.$el.fadeIn();
            }else{
                this.$el.fadeOut();
            }
        };
    
        //暴露模塊接口,返回整個對象
        return{
            BackTop: BackTop
        };
    
    
    });

第二步:scrollto.js保持不變

第三步:寫main.js入口文件

//定義別名
    requirejs.config({
        paths: {
            jquery: 'jquery-3.1.0'
        }
    });
    
    //調用backtop.js模塊
    requirejs(['jquery', 'backtop'], function($, backtop){
        //實例化BackTop
        new backtop.BackTop($('#backtop'),{
            mode: 'move',
            pos:100,
            speed: 2000
        });

    });

4.總結

這個demo中的模塊化是這樣一種思想:

  1. 首先把功能函數放在一個模塊中(move和go)

  2. 把整個實現功能也抽象成一個模塊,依賴上一個功能函數模塊

  3. 最後只須要在入口文件中實例化一下這個最外層的模塊,便可完成一系列功能的調用。

  4. 每一個模塊都用面向對象的思想,定義模塊而且暴露接口

  5. 默認值的用法可讓調用者拿起就用,能夠不用考慮傳參數。

相關文章
相關標籤/搜索