BUI 模塊

2020-08-11 17:08 更新

前言

隨著應(yīng)用的功能逐漸豐富,邏輯的復(fù)雜度不斷的增加,多人協(xié)作等問題, BUI有了自己的模塊化方案, 類似requirejs的AMD. 熟悉requirejs,seajs都可以很好的適應(yīng)過來.

模塊化解決什么問題?

  • 命名沖突
  • 文件依賴
  • 多人協(xié)作
  • 可維護(hù)性
  • 跨頁面共享

定義模塊

window.loader 默認(rèn)注冊(cè)給了 bui.loader. 關(guān)于loader的用法,可以查看 bui.loader API.

loader.define

loader.define 定義一個(gè)匿名模塊.

loader.define(function(require,exports,module){


    // 以下幾個(gè)參數(shù)非必須,如果前面加載了依賴,則這三個(gè)參數(shù)后移;
    // require : 相當(dāng)于 loader.require, 獲取依賴的模塊
    // exports : 如果沒有return 可以采用這種方式輸出模塊
    // module : 拿到當(dāng)前模塊信息


    // 第一次加載會(huì)執(zhí)行一次


    // 模塊如果需要給其它模塊加載,通過 return 的方式拋出來,或者module.exports的方式
    return {};
})

定義模塊需要遵循什么?

  1. 一個(gè)js 文件里面只能有一個(gè) loader.define 的匿名模塊;
  2. 業(yè)務(wù)邏輯需要在 loader.define 里面,防止加載其它模塊的時(shí)候沖突;
  3. 避免循環(huán)依賴 A ->依賴 B 模塊, 而 B模塊 -> A模塊, 這就造成循環(huán)依賴,一般需要避免這種設(shè)計(jì),如果一定要用, 不使用依賴前置的方式;
  4. 避免循環(huán)嵌套自身, 在loader.define 里面 又 require 加載當(dāng)前模塊, 這個(gè)時(shí)候還沒實(shí)例化,就會(huì)造成死循環(huán);
  5. 作為依賴的模塊, 里面不要執(zhí)行, 應(yīng)該返回對(duì)象給外層調(diào)用的方式;

加載模塊

loader.require

假設(shè)我們定義了一個(gè)匿名模塊, 是在pages/page2/目錄下, 目錄下有 page2.html ,page2.js 兩個(gè)文件. 則默認(rèn)匿名模塊的 模塊名是 pages/page2/page2 會(huì)根據(jù).html 文件提取前面路徑作為模塊名.

page2.js

loader.define(function(require,exports,module){


    // 定義初始化
    function init(text){
      // console.log("init:"+text)
    }


    // 自執(zhí)行初始化, 如果要給tab 使用,建議不要自執(zhí)行.
    init("第一次會(huì)自執(zhí)行");


    // 拋出方法及變量給外部訪問.
    return {
      init: init,
      pageName: "page2"
    }
})

現(xiàn)在我們想在剛剛的main.js里面加載這個(gè)模塊,調(diào)用pages/page2/page2 的名稱.

main.js

loader.define(function(require,exports,module){


    // 1. 加載pages/page2/page2模塊 方法1: 這里會(huì)自執(zhí)行一次 init. 輸出自執(zhí)行. 如果該模塊已經(jīng)加載過了,這里則不會(huì)執(zhí)行.
    require("pages/page2/page2"); 


    // 2. 有回調(diào)的時(shí)候,是會(huì)每次都執(zhí)行, 如果define的時(shí)候,有一次自執(zhí)行, 會(huì)變成執(zhí)行2次.
    require("pages/page2/page2",function(page2){
        // 這里會(huì)執(zhí)行第2次.
        page2.init("回調(diào)執(zhí)行")
    })


    return {
      pageName: "main"
    }
})

這樣打開首頁的時(shí)候,就會(huì)加載main.js, main.js 會(huì)去加載pages/page2/page2模塊,并調(diào)用對(duì)應(yīng)的方法.

造成重復(fù)執(zhí)行一般在tab比較常見, bui.tabto 事件是會(huì)每次都執(zhí)行, 如果 loader.require 的模塊有相同init回調(diào), 則每次都會(huì)執(zhí)行兩次, 解決的辦法是, 外部要操作里面的init方法時(shí), define 的時(shí)候,不要自執(zhí)行init.

模塊的定義及加載更多用法,請(qǐng)大家自行查閱 bui.loader API

加載文件資源

loader.import

沒有經(jīng)過define的第三方資源,又不想全局引用,可以使用loader.import動(dòng)態(tài)引入進(jìn)來. 例如,圖表控件.



例子1: 動(dòng)態(tài)加載單個(gè)樣式
loader.import("main.css",function(){
  // 創(chuàng)建成功以后執(zhí)行回調(diào)
});


例子2: 動(dòng)態(tài)加載單個(gè)腳本
loader.import("main.js",function(){
  // 創(chuàng)建成功以后執(zhí)行回調(diào)
});


例子3: 動(dòng)態(tài)加載多個(gè)腳本
loader.import(["js/plugins/baiduTemplate.js","js/plugins/map.js"],function(){
  // 創(chuàng)建成功以后執(zhí)行回調(diào)
});


例子4: 1.5.2新增, 動(dòng)態(tài)加載模板,回調(diào)每次都執(zhí)行, 如果放在 loader.require 里面執(zhí)行,則默認(rèn)只初始化一次;


loader.import("pages/ui/list.html",function(res){
  // 拿到模板信息
});


例子5: 1.5.4新增, 把html,渲染到某個(gè)id下,只渲染一次. 有回調(diào)也只執(zhí)行一次


loader.import("pages/ui/list.html","#id",function(res){
    // 在渲染模板到#id以后,回調(diào)只執(zhí)行一次
});

樣式的引入沒有局部作用域,所以加載樣式文件可能會(huì)造成影響全局,最好樣式還是統(tǒng)一sass模塊化管理.

同步加載多個(gè)文件

loader.importSync

如果需要同步加載多個(gè)文件, 應(yīng)該使用loader.importSync來替代loader.import;

例子: 動(dòng)態(tài)加載多個(gè)腳本
loader.importSync(["js/plugins/baiduTemplate.js","js/plugins/map.js"],function(){
  // 創(chuàng)建成功以后執(zhí)行回調(diào)
});

獲取及配置模塊

loader.map

可以用于設(shè)置或者獲取已經(jīng)加載的模塊的相關(guān)信息

例子1: 獲取所有模塊的配置信息
var map = loader.map();


例子2: 聲明單個(gè)模塊, router路由默認(rèn)聲明了main模塊,頁面打開會(huì)自動(dòng)加載該模板下的資源,也可以通過map去修改
修改首頁,必須在 window.router=bui.router(); 之后;


loader.map({
    moduleName: "main",
    template: "pages/main/main.html",
    script: "pages/main/main.js"
})


例子3: 定義多個(gè)模塊,并修改路徑
loader.map({
  baseUrl: "",
  modules: {
    "main": {
      moduleName: "main",
      template: "pages/main/main.html",
      script: "pages/main/main.js"
    }
    "home": {
      moduleName: "home",
      template: "pages/main/home.html",
      script: "pages/main/home.js"
    }
  }
})

注意:

  • 定義了模塊名以后,單頁跳轉(zhuǎn)則不能使用路徑跳轉(zhuǎn),而需要傳模塊跳轉(zhuǎn), 例如, router.load({url:"home"})
  • 如果loader.define的第一個(gè)參數(shù)有自定義名稱, 則還需要通過loader.map配置下模塊的路徑及模板指向.

獲取模塊的信息

1.5.3 新增

loader.get

var main = loader.get("main");

設(shè)置模塊的信息

1.5.3 新增

loader.set

如要設(shè)置main模塊, 必須在 window.router = bui.router() 之后, router.init 之前.

loader.set("main",{
  template:"pages/login/login.html",
  script: "pages/login/login.js"
});

頁面模塊的生命周期

1.5.3 新增. 需要配合路由使用,路由里面會(huì)去調(diào)用模塊定義的生命周期.

  • beforeCreate,create 只在模塊第一次創(chuàng)建的時(shí)候執(zhí)行,如果相同模塊第2次拿的是緩存, 不會(huì)觸發(fā);
  • beforeLoad,loaded 每次進(jìn)入頁面都會(huì)執(zhí)行, loaded 就相當(dāng)于 loader.define(function(){}) 里面的function;
  • show,hide 每次頁面前進(jìn)后退都會(huì)分別執(zhí)行, 可以通過形參拿到 show,hide 的 type 是 load, 還是 back, 默認(rèn)當(dāng)前頁刷新, 也會(huì)觸發(fā) show, type 則等于 firstload;
  • beforeDestroy,destroyed 每次后退前跟后退后執(zhí)行;

注意: beforeLoad 這里return false 并不能阻止頁面跳轉(zhuǎn)及執(zhí)行, 如果要阻止應(yīng)該在 bui.load({url:"",beforeLoad:function(){ return false; }}).

loader.define({
    beforeCreate: function() {
        // 只在創(chuàng)建腳本前執(zhí)行,緩存的時(shí)候不執(zhí)行
        console.log(this.moduleName + " before create")
    },
    created: function() {
        // 只在創(chuàng)建后執(zhí)行,緩存的時(shí)候不執(zhí)行
        console.log(this.moduleName + " createed")
    },
    beforeLoad: function() {
        // 頁面每次跳轉(zhuǎn)前都會(huì)執(zhí)行
        console.log(this.moduleName + " before load")
    },
    loaded: function() {
        // 頁面每次跳轉(zhuǎn)后都會(huì)執(zhí)行
        console.log(this.moduleName + " loaded")
    },
    hide: function(e) {
        // 頁面每次跳轉(zhuǎn)后退都會(huì)執(zhí)行當(dāng)前模塊的觸發(fā)
        console.log(this.moduleName + " hide")
        console.log(e.type)
    },
    show: function(e) {
        // 頁面每次跳轉(zhuǎn)后退都會(huì)執(zhí)行當(dāng)前模塊的觸發(fā)
        console.log(this.moduleName + " show")
        console.log(e.type)
    },
    beforeDestroy: function() {
        // 頁面每次后退前執(zhí)行
        console.log(this.moduleName + " before destroy")
    },
    destroyed: function() {
        // 頁面每次后退后執(zhí)行
        console.log(this.moduleName + " destroyed")
    }
})

當(dāng)然,你依然可以使用默認(rèn)最簡(jiǎn)單的模塊創(chuàng)建方式, 只是特殊模塊你可以給它自己的生命周期, 比方我在列表頁面,進(jìn)去詳情頁, 后退到列表頁, 是不會(huì)刷新的, 之前的方式是在后退的時(shí)候執(zhí)行某個(gè)方法. 現(xiàn)在只要在 show 的這個(gè)生命周期里, 我可以調(diào)用這個(gè)頁面的某個(gè)局部刷新的方法, 不管是前進(jìn)后退, 都可以執(zhí)行.

例子: 利用生命周期實(shí)現(xiàn)后退刷新.

loader.define({
    loaded: function() {
        this.pageview = {};


        // 初始化
        this.pageview.init = function(){


        }
        // 局部刷新
        this.pageview.refresh = function(){


        }


        // 這個(gè)是拋出給 loader.require 訪問的, 不能return this
        return this.pageview;
    },
    show: function(e) {


        // 后退才觸發(fā)刷新操作
        if( e.type == "back" ){
          this.pageview.refresh();
        }
    }
})

比方跳轉(zhuǎn)的頁面里面有個(gè)定時(shí)器, 后退的時(shí)候, 需要清理掉這個(gè)定時(shí)器, 這些是需要自己清除的.

loader.define({
    loaded: function() {
        // 頁面每次跳轉(zhuǎn)后都會(huì)執(zhí)行
        console.log(this.moduleName + " loaded")


        // 定時(shí)刷新
        this.timetoRefresh = window.setInterval(function(){
            // 4秒后執(zhí)行刷新
        },2000)
    },
    beforeDestroy: function() {
        // 頁面每次后退前執(zhí)行
        console.log(this.moduleName + " before destroy")


        if( this.timetoRefresh ){
          window.clearInterval(this.timetoRefresh);
        }
    }
})

還有一些比較有用的方法, 會(huì)在組件那里介紹.

疑難解答

1.如何拋出當(dāng)前模塊的方法共享

  1. 推薦 使用return 的方式 ;
    2. 使用module.exports 的方式;
    3. exports 的方式;
    使用任意一種就可以.

2.微信調(diào)試的緩存問題怎么解決?

在 index.js 配置bui.loader的cache參數(shù) 初始化必須在 window.router 前面

window.loader = bui.loader({
    cache: false
})

3.為什么不直接采用requirejs或者seajs呢?

這兩種方式都有在項(xiàng)目中使用,這樣模塊的復(fù)用及開發(fā)方式就無法統(tǒng)一,A項(xiàng)目開發(fā)完的部分模塊,可能B項(xiàng)目也能用,但兩者各自用的模塊化方式不同, 這就需要熟悉的人去做一定的修改. 采用我們自己的模塊化方式,可以跟bui.router路由更好的配合, 后面模塊化的公共插件也會(huì)越來越多, 這是我們以后希望看到的.

4.如何定義模塊的依賴呢?

main.js

// 依賴前置, 這種會(huì)優(yōu)先加載完 page2,page3模塊以后再執(zhí)行main的回調(diào). page2,page3 只定義,不執(zhí)行.
loader.define(["pages/page2/page2","pages/page3/page3"],function(page2,page3,require,exports,module){
  // 如果需要用到當(dāng)前模塊信息的話, page3后面依次還有 require,exports,module


})

5.如何定義一個(gè)自定義名字的模塊呢?

第1種:

  • 第1步: 聲明自定義模塊, 名稱需要跟映射的模塊名一致

pages/page2/page2.js

loader.define("page2",function(require,exports,module){
  // 這里是page2的業(yè)務(wù)邏輯
})

  • 第2步: 在首頁 index.html 的 bui.js 下面引入該文件.

index.html

<script src="js/bui.js"></script>
<!-- 加入自定義模塊 -->
<script src="pages/page2/page2.js"></script>

第2種:

  • 第1步: 映射腳本路徑

index.js

// 映射腳本路徑
loader.map({
  moduleName: "page2",
  script: "pages/page2/page2.js"
})


// 把路由實(shí)例化給 window.router 
window.router = bui.router();


bui.ready(function(){


})
  • 第2步: 聲明自定義模塊, 名稱需要跟映射的模塊名一致

pages/page2/page2.js

loader.define("page2",function(require,exports,module){
  // 這里是page2的業(yè)務(wù)邏輯
})

模塊的定義及加載更多用法,請(qǐng)大家自行查閱 bui.loader API

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)