BUI 單頁路由

2020-08-12 11:01 更新

前言

單頁路由可以實現(xiàn)對路由的復(fù)雜操作, 彌補多頁開發(fā)的不足, 在體驗上, 效果也會更佳. 每一個單頁都是一個組件.

單頁的原理是通過ajax請求,把其它頁面以局部加載的方式,渲染到路由里面, 那頁面重復(fù)加載就勢必會導(dǎo)致ID重復(fù), 必須遵守以下幾個原則.

  1. 使用 router.$ 替換 $ 選擇器; 例如:
    • 獲取或者設(shè)置 $("#id").text() 改成 router.$("#id").text();
    • 事件綁定 $("#id").click(function(){}) 改成 router.$("#id").click(function(){}) 才能確保你操作的是當(dāng)前頁面選擇器.
    • $.each $.extend ... 這類非選擇器的操作無需改變;
  2. 加載過的頁面, 使用后退刷新處理;

  • 例如: 從首頁 main 跳轉(zhuǎn)到登錄頁, 在登錄的時候,就應(yīng)該使用后退頁面刷新或者局部刷新處理, 而不是使用 bui.load 繼續(xù)跳轉(zhuǎn); 可以了解下登錄權(quán)限.

  1. 樣式?jīng)]有局部作用域, 需要手動加上父級選擇器;
  2. 路徑問題;

  • 例如: /pages/ui/list.htmlpages/ui/list.html是不一樣的, 在打包以后, /開頭的文件將會從內(nèi)存的根目錄開始查找, 會導(dǎo)致404, 應(yīng)該統(tǒng)一使用相對 index.html路徑的寫法 pages/ui/list.html.

  1. 頁面預(yù)覽;

  • 單頁里面只有模板跟模塊, 直接打開里面什么都沒有, 可以通過index.html#+模塊名的方式進(jìn)行預(yù)覽. index.html#pages/ui_controls/bui.list

效果預(yù)覽

單頁示例預(yù)覽

點擊這里體驗

路由功能

  • 頁面跳轉(zhuǎn),支持html跳轉(zhuǎn)或者模塊跳轉(zhuǎn);
  • 支持選擇不同動畫,融入不同平臺的切換效果;
  • 支持預(yù)加載;
  • 支持頁面刷新;
  • 支持當(dāng)前頁面替換;
  • 支持頁面的局部加載;
  • 支持頁面?zhèn)鲄?獲取參數(shù);
  • 支持指定跳入某個頁面;
  • 支持緩存,默認(rèn)已經(jīng)配置;
  • 支持展示進(jìn)度條,需要配置;
  • 支持后退刷新;
  • 支持后退多層;
  • 支持后退到指定模塊;
  • 支持物理后退按鍵;

創(chuàng)建單頁工程

使用buijs命令行構(gòu)建. 建議版本在1.6.0以上, 如何使用buijs命令行工具?

buijs 創(chuàng)建工程預(yù)覽

創(chuàng)建demo工程

## 創(chuàng)建目錄
$ mkdir demo


## 進(jìn)入demo目錄
$ cd demo


## 創(chuàng)建單頁工程
$ buijs create

安裝依賴及預(yù)覽

## 安裝工程依賴
$ npm install
## 運行服務(wù)并預(yù)覽
$ npm run dev

目錄規(guī)范

BUI 單頁示例目錄說明

目錄說明:

目錄名 描述 是否必須
/app.json 插件及跨域的配置
/gulpfile.js gulp編譯配置
/package.json 工程依賴配置
/src/index.html 應(yīng)用首頁入口文件
/src/index.js 路由的初始化腳本及全局事件
/src/css/ 應(yīng)用樣式及bui.css樣式
/src/font/ bui.css用到的字體圖標(biāo)
/src/images/ 應(yīng)用圖片目錄
/src/js/ 應(yīng)用腳本
/src/js/zepto.js bui.js默認(rèn)依賴于zepto.js 或 jquery
/src/js/bui.js BUI交互控件庫
/src/pages/ 應(yīng)用的模塊
/src/pages/main/ 默認(rèn)路由初始化以后會先載入這個main模塊
/src/pages/main/main.html main模塊的模板
/src/pages/main/main.js main模塊的業(yè)務(wù)腳本

路由初始化

打開編輯 src/index.html , body 下只有一個div,這個便是路由最外層結(jié)構(gòu).

src/index.html

<!DOCTYPE HTML>
<html lang="en-US">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
    <title>BUI單頁工程</title>
    <meta name="format-detection" content="telephone=no" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
    <link rel="stylesheet" href="css/bui.css" />
</head>


<body>
    <!-- 第1步: 開啟單頁路由 -->
    <div id="bui-router"></div>
    <script src="js/zepto.js"></script>
    <script src="js/bui.js"></script>
    <!-- 初始化單頁 -->
    <script src="index.js"></script>
</body>


</html>

src/index.js

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


bui.ready(function(){


    // 加載頁面到div容器里面, 更多參數(shù)請查閱API
    router.init({
        id: "#bui-router"
    })
})

當(dāng)路由初始化以后,會自動查找首頁main模塊, 這個模塊是內(nèi)部定義好的, 默認(rèn)指向路徑 pages/main/main.html自動加載相同名字的js文件. 除了main, 正常我們都是創(chuàng)建匿名模塊,這樣只要通過路徑跳轉(zhuǎn),就會自動加載相對路徑同名的模塊.

模塊名: main

src/pages/main/main.html

<div class="bui-page">
    <header class="bui-bar">
        <div class="bui-bar-left">
        </div>
        <div class="bui-bar-main">main</div>
        <div class="bui-bar-right">
        </div>
    </header>
    <main>
      <div id="btn" class="bui-btn">跳轉(zhuǎn)page2.html</div>
    </main>
    <footer></footer>
</div>

src/pages/main/main.js

loader.define(function(require,exports,module){
    // 綁定按鈕跳轉(zhuǎn)
    $("#btn").on("click",function(){
      bui.load({ url: "pages/page2/page2.html", param: {} });
    })
})

pages/page2/page2模塊

我們再創(chuàng)建一個 src/pages/page2/page2.html,及 src/pages/page2/page2.js ,那通過上面的方式跳轉(zhuǎn),則創(chuàng)建了一個 src/pages/page2/page2 的模塊.

src/pages/page2/page2.html

<div class="bui-page">
    <header class="bui-bar">
        <div class="bui-bar-left">
        </div>
        <div class="bui-bar-main">page2</div>
        <div class="bui-bar-right">
        </div>
    </header>
    <main></main>
    <footer></footer>
</div>

src/pages/page2/page2.js

loader.define(function(require,exports,module){
  // 腳本都需要在這里執(zhí)行


})

注意:

  • 頁面已經(jīng)加載過,應(yīng)該使用后退操作, 例如,上面的例子,在pages2.html,不要使用 router.load({url:"main"}) 這樣跳回首頁, 使用 router.back;

頁面跳轉(zhuǎn)

router.load(option)

頁面跳轉(zhuǎn),保持js跟html一致的命名,才能自動加載觸發(fā). 同樣支持 bui.btn 靜態(tài)跳轉(zhuǎn)

參數(shù): option是一個對象

option.url

  • Type: string
  • Detail: 相對路徑

option.param

  • Type: object
  • Detail: 傳給目標(biāo)頁面的參數(shù)

例子:

router.load({ url: "pages/page2/page2.html", param: {} });
// 路由初始化以后,下面的跳轉(zhuǎn)也是單頁跳轉(zhuǎn)
bui.load({ url: "pages/page2/page2.html", param: {} });

注意: 仔細(xì)查看下跟多頁路由接口都是保持的一致,甚至你可以直接使用 bui.load 來代替 router.load , 這個也是最早我們推薦的方式, 所以你會看到部分例子還是保持這樣的寫法.

接收參數(shù)

router.getPageParams

接收到的參數(shù)為一個對象, 無需在回調(diào)里面拿.

例子:

var params = router.getPageParams();

頁面后退

router.back(option)

router.back 跟 bui.back 的區(qū)別在于, bui.back 后退會把歷史記錄一起后退,router.back 只是后退頁面. 開發(fā)中推薦使用 bui.loadbui.back.

參數(shù): option是一個對象

option.index

  • Type: number
  • Detail: 后退幾層,默認(rèn):-1

option.name

  • Type: string
  • Detail: 后退到指定的模塊名, name跟index,只能有一個

option.callback

  • Type: function
  • Detail: 后退以后執(zhí)行回調(diào)

例子:

// 普通后退
router.back();


// 后退局部刷新
router.back({
  callback: function(module){
    // 后退的頁面有拋出一個init方法 或者刷新方法, 做內(nèi)容修改
    module.init();
  }
});


// 后退2層刷新
bui.back({
  index: -2,
  callback: function(){
    bui.refresh()
  }
});


// 不管在哪層,都可以后退到首頁
bui.back({
  name: "main"
});

頁面替換

router.replace(option)

頁面替換不會增加歷史記錄

參數(shù): option是一個對象

option.url

  • Type: string
  • Detail: 相對路徑

option.param

  • Type: object
  • Detail: 傳給目標(biāo)頁面的參數(shù)

例子:

router.replace({ url: "pages/page3/page3.html" });

局部加載模塊

router.loadPart

參數(shù): option是一個對象

option.id

  • Type: string|object
  • Detail: 局部的id或者對象

option.url

  • Type: string
  • Detail: 相對路徑

option.param

  • Type: object
  • Detail: 傳給目標(biāo)頁面的參數(shù)

例子:

router.loadPart({ id:"#part", url: "pages/page2/page2.html", param: {} });

局部加載在1.6.x 有更簡單的方式, 使用 component標(biāo)簽, 便可自動加載.

<component name="pages/page2/page2"></component>

局部接收參數(shù)

router.getPartParams(moduleName)

參數(shù):

moduleName

  • Type: string
  • Detail: 模塊的名稱

例子:

loader.define(function(require,exports,module) {
  // module 為當(dāng)前的模塊信息
   var pid = module.moduleName,
       params = router.getPartParams(pid);


 })

預(yù)加載

router.preload(option)

如果你的應(yīng)用是webapp,那這個功能就比較好用了,先在首頁預(yù)加載想要觸發(fā)的頁面, 當(dāng)點擊觸發(fā)相同頁面的時候, 你會發(fā)現(xiàn)跳轉(zhuǎn)速度快多了, 本地應(yīng)用則無需使用到預(yù)加載.

參數(shù): option是一個對象

option.url

  • Type: string
  • Detail: 緩存模板

option.script

  • Type: string
  • Detail: 緩存腳本

// 預(yù)加載一個頁面
router.preload({ url: "pages/page2/page2.html" });


// 預(yù)加載多個頁面
router.preload([{ 
  url: "pages/page2/page2.html" 
},{ 
  url: "pages/page3/page3.html" 
}]);

頁面重復(fù)加載

頁面重復(fù)加載的表現(xiàn)通常是, 渲染出不來,要刷新才有數(shù)據(jù). 事件被重復(fù)綁定等.

使用 router.$ 替換 $ 選擇器

router.$$的區(qū)別在于, router.$ 是相對于當(dāng)前路由的頁面查找, 有一種情況, 頁面需要被重復(fù)加載, 比方列表頁,跳轉(zhuǎn)到詳情頁,詳情頁又有推薦的列表,點擊又會跳轉(zhuǎn)到詳情, 這種時候,$綁定頁面的事件會被重復(fù)綁定, router.$ 則不會.

事件綁定示例:

// 靜態(tài)的結(jié)構(gòu)綁定事件
router.$(".bui-page .btn").click(function(e){


})

另外,建議一個單頁應(yīng)用的層級建議控制在 5級左右. 已經(jīng)加載過的頁面,使用后退刷新處理. 例如:

// 推薦: 這也是微信小程序里面推薦的層級數(shù)
A->B->C->D->E 


// 不要這樣, 這種做法本身會讓用戶陷入混亂
A->B->C->B->C

路由全局事件

load 事件

頁面加載,在模板加載完成就會觸發(fā),有緩存的時候只觸發(fā)一次

router.on("load",function(e){
  // 獲取當(dāng)前頁的模塊
  console.log(e.target);
  // 獲取上一頁的模塊
  console.log(e.prevTarget);
})

complete 事件

頁面完成,每次加載完模板都會觸發(fā)

router.on("complete",function(e){
  // 獲取當(dāng)前頁的模塊
  console.log(e.target);
  // 獲取上一頁的模塊
  console.log(e.prevTarget);
})

back 事件

router.on("back",function(e){
  // 獲取當(dāng)前頁的模塊
  console.log(e.target);
  // 獲取上一頁的模塊
  console.log(e.prevTarget);
})

refresh 事件

router.on("refresh",function(e){
  // 獲取當(dāng)前頁的模塊
  console.log(e.target);
  // 獲取上一頁的模塊
  console.log(e.prevTarget);
})

loadpart 事件

頁面局部加載后觸發(fā)

router.on("loadpart",function(e){
  // 獲取當(dāng)前頁子模塊
  console.log(e.target);
  // 獲取當(dāng)前頁父模塊
  console.log(e.prevTarget);
})

注意: 建議全局事件都在 index.js 加載. 事件名全部為小寫.

單頁生命周期

路由原理

這是路由加載的完整過程.

BUI 路由模塊加載流程圖

路由加載路線說明

  • ① 為首頁 main 的自定義模塊加載, 已經(jīng)配置了路徑指向, 你可以通過 indexModule 參數(shù)修改main首頁的指向;
  • ② 為沒有自定義模塊的時候, 點擊后走相對根路徑的同名文件模塊;
  • ③ 為跳轉(zhuǎn)已經(jīng)加載過的模塊;
  • ④ 為只有模板,沒有同名腳本路徑走的路線;

路線①: 自定義的main模塊加載

BUI main模塊的加載

路線②: 點擊跳轉(zhuǎn)的頁面加載, 默認(rèn)跳轉(zhuǎn)的路徑就是模塊名

路線③: 已經(jīng)加載過的頁面,只需走loaded回調(diào).

BUI 點擊跳轉(zhuǎn)的模塊加載

路由加載注意事項

  1. 打開路由及跳轉(zhuǎn)頁面都會先加載模板,再加載腳本;
  2. 單頁只需要在首頁執(zhí)行一次 bui.ready;
  3. 路由的初始化也必須在 bui.ready 里面執(zhí)行;
  4. 模塊里面的選擇器使用 router.$ 替換 $ ,確保你操作的是當(dāng)前頁面的模塊的dom;
  5. 如果需要修改 bui.loader 需要在 window.router 之前;
  6. 路由的全局事件, 必須在 index.js 才能使用, 不能放在單獨的模塊里.

生命周期

1.5.3 新增, 路由跳轉(zhuǎn)頁面會觸發(fā)模塊的加載, 從進(jìn)入頁面,跳轉(zhuǎn)頁面,后退頁面完成一個頁面的生命周期.

頁面展示的生命周期

這是打開路由第一次加載 main模塊以后觸發(fā)的加載.

BUI 模塊的加載會觸發(fā)模塊的生命周期

頁面跳轉(zhuǎn)后退之間的生命周期

BUI 模塊的加載會觸發(fā)模塊的生命周期

一. 跳轉(zhuǎn):

1, main模塊

① 未定義生命周期, 只執(zhí)行 loaded .

2, main->A 頁面

① A頁面定義了生命周期, 從 beforeCreate -> created -> beforeLoad -> loaded -> show , 這是A頁面的顯示生命周期. ② 從main->第2次跳轉(zhuǎn)到A頁面的時候, 直接走 beforeLoad -> loaded -> show;

3, A頁面->B頁面, 會執(zhí)行 A頁面自身的 hide 再跳去 B頁面的 ① beforeCreate -> created -> beforeLoad -> loaded -> show

二. 后退:

  1. B->A 頁面 B跟A都有自己的生命周期, 后退的時候會先執(zhí)行 當(dāng)前頁的hide ->beforeDestroy -> destroyed , 然后還會觸發(fā) A頁面的 show 方法.
  2. A->main 頁面 由于main沒有定義show方法, 所以只執(zhí)行A頁面的 hide ->beforeDestroy -> destroyed

使用

具體查看模塊的定義. 頁面模塊的生命周期

接下來你可以繼續(xù)學(xué)習(xí)

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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號