BUI 組件通訊

2020-08-12 14:03 更新

以下內(nèi)容基于BUI 1.6.2版本.

組件通訊圖

組件通訊圖

路由初始化以后就會去找 main 入口頁, 假設(shè)main由3個組件組成, 會依次,從上到下加載組件, 加載以后再遞歸查找子組件, 如此反復(fù). (雖然默認(rèn)組件允許嵌套組件, 但我們依然不建議把頁面拆得太散. 組件應(yīng)該是一個可以被自由加載,獨(dú)立運(yùn)行的個體. )

父組件傳參給子組件

1. 靜態(tài)傳參

一進(jìn)頁面的時候就會編譯, 這種組件應(yīng)該是能夠獨(dú)立運(yùn)行的.

  1. <component id="list" name="pages/components/list/index" type="news"></component>

2. 動態(tài)傳參

組件需要通過請求以后才知道有哪些參數(shù), 靜態(tài)參數(shù)改變不會實時變更.

  1. <component id="list" name="pages/components/list/index" delay="true"></component>

  1. // 點(diǎn)擊或者請求以后才加載
  2. $("#id").click(function(){
  3. // 動態(tài)加載組件
  4. loader.delay({
  5. id: "#list",
  6. param: {"type":"news"}
  7. })
  8. })

3. 接收參數(shù)

list組件 pages/components/list/index.js

  1. loader.define(function(require,export,module){
  2. // 接收父級的傳參
  3. var param = bui.history.getParams(module.id)
  4. // param.type = news
  5. })

子組件獲取父組件

list組件 pages/components/list/index.js

  1. loader.define(function(require,export,module){
  2. // 1.6.1 的方式
  3. var params = bui.history.getParams(module.id);
  4. var parentComp = bui.history.getComponent(params.parentId);
  5. // 1.6.2 的方式
  6. var parentComp = bui.history.getParentComponent();
  7. // 拿到父組件return 出來的方法, 就可以操作父組件.
  8. })

如果列表組件沒有被嵌套加載, 拿到的父組件為頁面組件, 嵌套則是拿到上一級組件.

子組件獲取頁面組件

list組件 pages/components/list/index.js

  1. loader.define(function(require,export,module){
  2. // 無論被嵌套多少層都可以直接獲取到頁面組件
  3. var pageComp = bui.history.getLast("exports");
  4. })

兄弟組件

比方頁面由 搜索組件, 列表組件 組成, 點(diǎn)擊搜索, 要操作列表的方法重新帶上關(guān)鍵字請求;

頁面組件 pages/main/main.html

  1. <div class="bui-page bui-box-vertical">
  2. <header></header>
  3. <main>
  4. <!-- 搜索組件 -->
  5. <component id="search" name="pages/components/searchbar/index"></component>
  6. <!-- 列表組件 -->
  7. <component id="list" name="pages/components/list/index"></component>
  8. </main>
  9. </div>

search組件 pages/components/search/index.js

  1. loader.define(function(require,export,module){
  2. var pageview = {
  3. init: function(){
  4. // 這樣是獲取不到list組件的 refresh 方法, 因為list比search晚加載.
  5. // var list = bui.history.getComponent("list");
  6. router.$("#btnSearch").click(function(){
  7. // 在點(diǎn)擊的時候可以獲取到兄弟list組件.
  8. var list = bui.history.getComponent("list");
  9. // 獲取搜索的關(guān)鍵字
  10. var keyword = router.$(".search-input").val();
  11. // 調(diào)用列表組件的局部屬性方法, 把關(guān)鍵字傳過去.
  12. list.refresh(keyword);
  13. })
  14. }
  15. }
  16. // 初始化
  17. pageview.init();
  18. return pageview
  19. })

list組件 pages/components/list/index.js

  1. loader.define(function(require,export,module){
  2. var pageview = {
  3. init: function(){
  4. },
  5. refresh: function(keyword){
  6. // 接收到搜索傳來的關(guān)鍵字進(jìn)行請求操作
  7. console.log(keyword)
  8. }
  9. }
  10. // 初始化
  11. pageview.init();
  12. return pageview
  13. })

注意, 搜索組件在初始化直接獲取list組件, 會獲取不到, 因為list比search晚加載.

父組件獲取子組件

父組件獲取子組件由于加載順序, 如果組件被重復(fù)加載,那就會重復(fù)觸發(fā) one里面的回調(diào). 應(yīng)該盡量避免這種操作.

1. 頁面組件獲取子組件

main頁面組件: pages/main/main.html

  1. <component id="searchbar" name="pages/components/searchbar/index"></component>
  2. <component id="list" name="pages/components/list/index"></component>

pages/main/main.js

  1. loader.define(function(){
  2. // 監(jiān)聽 多個子組件加載完成就會觸發(fā)一次
  3. loader.wait(["searchbar","list"],function(searchbar,list){
  4. // 拿到子組件實例操作
  5. console.log(searchbar.exports)
  6. console.log(list.exports)
  7. })
  8. })

2. 自定義事件獲取

main頁面組件: pages/main/main.html

  1. <component id="list" name="pages/components/list/index"></component>

pages/main/main.js

  1. loader.define(function(require,export,module){
  2. // 監(jiān)聽頁面點(diǎn)擊了搜索以后的操作
  3. loader.on("click-search",function(mod){
  4. // 拿到子組件操作
  5. mod.refresh();
  6. })
  7. })

pages/components/list/index.js

  1. loader.define(function(require,export,module){
  2. var pageview = {
  3. init: function(){
  4. // 綁定點(diǎn)擊事件
  5. router.$(".btn-search").click(function(){
  6. // 組件加載完成以后觸發(fā)自定義事件, 把對象傳給父組件操作.
  7. loader.trigger("click-search","傳過去的參數(shù)");
  8. })
  9. },
  10. refresh: function(){
  11. console.log("list refresh")
  12. }
  13. }
  14. // 初始化
  15. pageview.init();
  16. return pageview;
  17. })

綜合案例

搜索跟列表組件跟頁面組件相互操作的案例.

案例

圖片案例

例如: 待辦頁面, 頁面上有搜索組件,有list組件,還有tab組件. 點(diǎn)擊搜索如果在待辦列表,則搜索待辦數(shù)據(jù), 在已辦列表則搜索已辦數(shù)據(jù).
預(yù)覽效果. 點(diǎn)擊里面的源碼可以看到代碼, 但看不到效果.

主入口, 待辦已辦

我們在這里來分析下. 模板里面跟我們前面講的一個TAB的初始化是一樣的. 模板header有搜索組件,main有tab組件(容器組件不用做成component), tab組件又嵌套了list組件. 根據(jù)組件的名稱, 我們知道了組件的所在目錄, 新建了components目錄進(jìn)行集中管理, 并且組件的命名里面都是叫index,通過文件夾名稱區(qū)分組件名.

pages/main/main.html

  1. <div class="bui-page bui-box-vertical">
  2. <header>
  3. <div class="bui-bar">
  4. <div class="bui-bar-left">
  5. <a class="bui-btn" onclick="bui.back();"><i class="icon-back"></i></a>
  6. </div>
  7. <div class="bui-bar-main">待辦已辦</div>
  8. <div class="bui-bar-right">
  9. </div>
  10. </div>
  11. <component name="pages/components/searchbar/index"></component>
  12. </header>
  13. <main class="bui-scroll-hide">
  14. <div id="uiTab" class="bui-tab bui-box-vertical">
  15. <div class="bui-tab-head">
  16. <ul class="bui-nav">
  17. <li class="bui-btn">待辦</li>
  18. <li class="bui-btn">已辦</li>
  19. </ul>
  20. </div>
  21. <div class="bui-tab-main">
  22. <ul>
  23. <li>
  24. <component id="list0" name="pages/components/list/index" type="todo"></component>
  25. </li>
  26. <li style="display: none;">
  27. <component id="list1" name="pages/components/list/index" type="done" delay="true"></component>
  28. </li>
  29. </ul>
  30. </div>
  31. </div>
  32. </main>
  33. </div>

pages/main/main.js

在模塊的內(nèi)部組織里面,我們也新建了一個 pageview對象,并把 tab的實例接口拋出去. tab在切換的時候, 把之前延遲加載的組件編譯執(zhí)行了一遍, 下次點(diǎn)擊切換不會再繼續(xù)執(zhí)行.

  1. loader.define(function(){
  2. var pageview = {
  3. init: function() {
  4. // 拋出tab的實例,搜索控件需要用到
  5. this.tab = this.tabInit();
  6. },
  7. tabInit: function() {
  8. var uiTab = bui.tab({
  9. id: "#uiTab",
  10. scroll: false
  11. });
  12. // component 自動編譯延遲加載的component, 所以無需 to(0)
  13. uiTab.on("to", function() {
  14. // 索引從0開始
  15. var index = this.index();
  16. // 延遲加載有delay屬性的列表,跳到對應(yīng)的tab才加載
  17. loader.delay({
  18. id: "#list" + index
  19. })
  20. })
  21. return uiTab;
  22. }
  23. };
  24. // 執(zhí)行初始化
  25. pageview.init();
  26. // 拋出接口
  27. return pageview;
  28. })

列表刷新滾動加載組件

pages/components/list/index.html

  1. <div class="bui-scroll">
  2. <div class="bui-scroll-head"></div>
  3. <div class="bui-scroll-main">
  4. <ul class="bui-list">
  5. </ul>
  6. </div>
  7. <div class="bui-scroll-foot"></div>
  8. </div>

pages/components/list/index.js

list被同一個頁面加載, 因此初始化時, 需要通過父層id來區(qū)分不同控件, 并且通過不同參數(shù)來請求不同的接口. 剩下的交由控件自己處理分頁跟刷新. 把list實例拋出, 因為搜索的時候, 需要操作對應(yīng)的list實例.

  1. loader.define(function(require,exports,module){
  2. var pageview = {
  3. init: function(){
  4. // 獲取參數(shù)
  5. var params = bui.history.getParams(module.id)
  6. // 拋出list的實例
  7. this.list = this.listInit(params);
  8. },
  9. listInit: function(opt){
  10. if( this.list ){
  11. return this.list;
  12. }
  13. // 列表控件 js 初始化:
  14. var uiList = bui.list({
  15. id: `#${module.id} .bui-scroll`,
  16. url: "http://rap2api.taobao.org/app/mock/84605/example/getNews",
  17. pageSize:5,
  18. data: {
  19. type: opt.type
  20. },
  21. //如果分頁的字段名不一樣,通過field重新定義
  22. field: {
  23. page: "page",
  24. size: "pageSize",
  25. data: "data"
  26. },
  27. callback: function (e) {},
  28. template: function (data) {
  29. var html = "";
  30. data.forEach(function(el, index) {
  31. html +=`<li class="bui-btn bui-box">
  32. <div class="bui-thumbnail"><img src="${el.image}" alt=""></div>
  33. <div class="span1">
  34. <h3 class="item-title">${el.name}</h3>
  35. <p class="item-text">${el.address}</p>
  36. <p class="item-text">${el.distance}公里</p>
  37. </div>
  38. <span class="price"><i></i>${el.price}</span>
  39. </li>`
  40. });
  41. return html;
  42. }
  43. });
  44. return uiList;
  45. }
  46. }
  47. pageview.init();
  48. return pageview;
  49. })

搜索組件

pages/components/searchbar/index.html

  1. <div id="searchbar" class="bui-searchbar bui-box">
  2. <div class="span1">
  3. <div class="bui-input">
  4. <i class="icon-search"></i>
  5. <input type="search" value="" placeholder="請輸入出差人或同行人" />
  6. </div>
  7. </div>
  8. <div class="btn-search">搜索</div>
  9. </div>

pages/components/searchbar/index.js

一個頁面只有一個搜索欄, 這里并不需要通過外部id去進(jìn)行區(qū)分. 點(diǎn)擊搜索的時候, 通過 bui.history.getLast("exports") 獲取父級TAB實例, bui.history.getComponent("list0") 通過id來獲取對應(yīng)的list實例. 調(diào)用實例的方法, 把參數(shù)傳過去.

  1. loader.define(function(require,exports,module){
  2. var pageview = {
  3. init: function(){
  4. this.searchbar = this.searchbarInit();
  5. },
  6. searchbarInit: function(opt){
  7. //搜索條的初始化
  8. var uiSearchbar = bui.searchbar({
  9. id: `#searchbar`,
  10. callback: function (e, keyword) {
  11. // 獲取父級實例
  12. var lastDistance = bui.history.getLast("exports");
  13. var currentIndex = lastDistance.tab.index();
  14. // 根據(jù)索引獲取對應(yīng)的list實例,重新請求關(guān)鍵字
  15. var components = bui.history.getComponent("list"+currentIndex);
  16. components.list.empty();
  17. components.list.init({
  18. data: {
  19. keyword: keyword
  20. }
  21. });
  22. },
  23. onInput: function (e, keyword) {
  24. //實時搜索
  25. // console.log(++n)
  26. },
  27. onRemove: function (e, keyword) {
  28. //刪除關(guān)鍵詞需要做什么其它處理
  29. // console.log(keyword);
  30. }
  31. });
  32. return uiSearchbar;
  33. }
  34. }
  35. pageview.init();
  36. return pageview;
  37. })

最終效果

通過上面幾個文件的代碼, 就可以輕松實現(xiàn)下拉刷新,滾動加載下一頁,tab切換,自動根據(jù)選項卡觸發(fā)列表搜索,刪除關(guān)鍵字等功能.

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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號