BUI 組件通訊

以下內容基於BUI 1.6.2版本.

組件通訊圖

component-link.png

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

父組件傳參給子組件

1. 靜態傳參

一進頁面的時候就會編譯, 這種組件應該是能夠獨立運行的.

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

2. 動態傳參

組件需要通過請求以後才知道有哪些參數, 靜態參數改變不會實時變更.

<component id="list" name="pages/components/list/index" delay="true"></component>
// 點擊或者請求以後才加載
$("#id").click(function(){
    // 動態加載組件
    loader.delay({
      id: "#list",
      param: {"type":"news"}
    })
})

3. 接收參數

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

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

子組件獲取父組件

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

loader.define(function(require,export,module){
    // 1.6.1 的方式
    var params = bui.history.getParams(module.id);
    var parentComp = bui.history.getComponent(params.parentId);

    
    // 1.6.2 的方式
    var parentComp = bui.history.getParentComponent();
    // 拿到父組件return 出來的方法, 就可以操作父組件.

})

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

子組件獲取頁面組件

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

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

})

兄弟組件

?> 比方頁面由 搜索組件列表組件 組成, 點擊搜索, 要操作列表的方法重新帶上關鍵字請求;

頁面組件
pages/main/main.html

<div class="bui-page bui-box-vertical">
  <header></header>
  <main>
      <!-- 搜索組件 -->
      <component id="search" name="pages/components/searchbar/index"></component>
      <!-- 列表組件 -->
      <component id="list" name="pages/components/list/index"></component>
  </main>
</div>

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

loader.define(function(require,export,module){
    var pageview = {
      init: function(){
        // 這樣是獲取不到list組件的 refresh 方法, 因爲list比search晚加載.
        // var list = bui.history.getComponent("list");

        router.$("#btnSearch").click(function(){

            // 在點擊的時候可以獲取到兄弟list組件.
            var list = bui.history.getComponent("list");

            // 獲取搜索的關鍵字
            var keyword = router.$(".search-input").val();
            
            // 調用列表組件的局部屬性方法, 把關鍵字傳過去.
            list.refresh(keyword);
        })
      }
    }
    // 初始化
    pageview.init();
    return pageview
})

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

loader.define(function(require,export,module){
    var pageview = {
      init: function(){

      },
      refresh: function(keyword){
        // 接收到搜索傳來的關鍵字進行請求操作
        console.log(keyword)
      }
    }
    // 初始化
    pageview.init();
    return pageview
})

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

父組件獲取子組件

?> 父組件獲取子組件由於加載順序, 如果組件被重複加載,那就會重複觸發 one裏面的回調. 應該儘量避免這種操作.

1. 頁面組件獲取子組件

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

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

pages/main/main.js

loader.define(function(){
    // 監聽 多個子組件加載完成就會觸發一次
    loader.wait(["searchbar","list"],function(searchbar,list){
      // 拿到子組件實例操作
      console.log(searchbar.exports)
      console.log(list.exports)
    })
})

2. 自定義事件獲取

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

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

pages/main/main.js

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

    // 監聽頁面點擊了搜索以後的操作
    loader.on("click-search",function(mod){
      // 拿到子組件操作
      mod.refresh();
    })
})

pages/components/list/index.js

loader.define(function(require,export,module){
    var pageview = {
      init: function(){
        // 綁定點擊事件
        router.$(".btn-search").click(function(){

          // 組件加載完成以後觸發自定義事件, 把對象傳給父組件操作.
          loader.trigger("click-search","傳過去的參數");
        })
      },
      refresh: function(){
        console.log("list refresh")
      }
    }

    // 初始化
    pageview.init();

    return pageview;
})

綜合案例

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

<iframe width="320" height="560" src="http://www.easybui.com/demo/#pages/ui_loader/component" allowfullscreen="allowfullscreen" frameborder="0"></iframe>

?> 例如: 待辦頁面, 頁面上有搜索組件,有list組件,還有tab組件. 點擊搜索如果在待辦列表,則搜索待辦數據, 在已辦列表則搜索已辦數據.
預覽效果. 點擊裏面的源碼可以看到代碼, 但看不到效果.

主入口, 待辦已辦

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

tab-list2.gif

pages/main/main.html

<div class="bui-page bui-box-vertical">
    <header>
        <div class="bui-bar">
            <div class="bui-bar-left">
                <a class="bui-btn" onclick="bui.back();"><i class="icon-back"></i></a>
            </div>
            <div class="bui-bar-main">待辦已辦</div>
            <div class="bui-bar-right">
            </div>
        </div>
        <component name="pages/components/searchbar/index"></component>
    </header>
    <main class="bui-scroll-hide">
        <div id="uiTab" class="bui-tab bui-box-vertical">
            <div class="bui-tab-head">
                <ul class="bui-nav">
                    <li class="bui-btn">待辦</li>
                    <li class="bui-btn">已辦</li>
                </ul>
            </div>
            <div class="bui-tab-main">
                <ul>
                    <li>
                        <component id="list0" name="pages/components/list/index" type="todo"></component>
                    </li>
                    <li style="display: none;">
                        <component id="list1" name="pages/components/list/index" type="done" delay="true"></component>
                    </li>
                </ul>
            </div>
        </div>
    </main>
</div>

pages/main/main.js

?> 在模塊的內部組織裏面,我們也新建了一個 pageview對象,並把 tab的實例接口拋出去. tab在切換的時候, 把之前延遲加載的組件編譯執行了一遍, 下次點擊切換不會再繼續執行.

loader.define(function(){
    var pageview = {
        init: function() {
            // 拋出tab的實例,搜索控件需要用到
            this.tab = this.tabInit();
        },
        tabInit: function() {
            var uiTab = bui.tab({
                id: "#uiTab",
                scroll: false
            });

            // component 自動編譯延遲加載的component, 所以無需 to(0)
            uiTab.on("to", function() {
                // 索引從0開始
                var index = this.index();
                // 延遲加載有delay屬性的列表,跳到對應的tab才加載
                loader.delay({
                    id: "#list" + index
                })
            })

            return uiTab;
        }
    };
    // 執行初始化
    pageview.init();
    // 拋出接口
    return pageview;
})

列表刷新滾動加載組件

tab-list1.gif

pages/components/list/index.html

<div class="bui-scroll">
    <div class="bui-scroll-head"></div>
    <div class="bui-scroll-main">
        <ul class="bui-list">
        </ul>
    </div>
    <div class="bui-scroll-foot"></div>
</div>

pages/components/list/index.js

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

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

    var pageview = {
      init: function(){
        // 獲取參數
        var params = bui.history.getParams(module.id)

        // 拋出list的實例
        this.list = this.listInit(params);
      },
      listInit: function(opt){
        if( this.list ){
          return this.list;
        }
        // 列表控件 js 初始化:
        var uiList = bui.list({
            id: `#${module.id} .bui-scroll`,
            url: "http://rap2api.taobao.org/app/mock/84605/example/getNews",
            pageSize:5,
            data: {
              type: opt.type
            },
            //如果分頁的字段名不一樣,通過field重新定義
            field: {
                page: "page",
                size: "pageSize",
                data: "data"
            },
            callback: function (e) {},
            template: function (data) {
                var html = "";
                data.forEach(function(el, index) {

                    html +=`<li class="bui-btn bui-box">
                        <div class="bui-thumbnail"><img src="${el.image}" alt=""></div>
                        <div class="span1">
                            <h3 class="item-title">${el.name}</h3>
                            <p class="item-text">${el.address}</p>
                            <p class="item-text">${el.distance}公里</p>
                        </div>
                        <span class="price"><i>¥</i>${el.price}</span>
                    </li>`
                });

                return html;
            }
        });
        return uiList;
      }
    }

    pageview.init();

    return pageview;
})

搜索組件

tab-list3.gif
pages/components/searchbar/index.html

<div id="searchbar" class="bui-searchbar bui-box">
    <div class="span1">
        <div class="bui-input">
            <i class="icon-search"></i>
            <input type="search" value="" placeholder="請輸入出差人或同行人" />
        </div>
    </div>
    <div class="btn-search">搜索</div>
</div>

pages/components/searchbar/index.js

?> 一個頁面只有一個搜索欄, 這裏並不需要通過外部id去進行區分. 點擊搜索的時候, 通過 bui.history.getLast("exports") 獲取父級TAB實例, bui.history.getComponent("list0") 通過id來獲取對應的list實例. 調用實例的方法, 把參數傳過去.

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

    var pageview = {
      init: function(){
        this.searchbar = this.searchbarInit();
      },
      searchbarInit: function(opt){
        //搜索條的初始化
        var uiSearchbar = bui.searchbar({
            id: `#searchbar`,
            callback: function (e, keyword) {
              // 獲取父級實例
                var lastDistance = bui.history.getLast("exports");
                var currentIndex = lastDistance.tab.index();
                // 根據索引獲取對應的list實例,重新請求關鍵字
                var components = bui.history.getComponent("list"+currentIndex);
                components.list.empty();
                components.list.init({
                      data: {
                        keyword: keyword
                      }
                });
            },
            onInput: function (e, keyword) {
                //實時搜索
                // console.log(++n)
            },
            onRemove: function (e, keyword) {
                //刪除關鍵詞需要做什麼其它處理
                // console.log(keyword);
            }
        });
        return uiSearchbar;
      }
    }

    pageview.init();
    return pageview;
})

最終效果

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

tab-list4.gif


buishensu.png

碼字不易, 歡迎關注bui神速, 跟我們一起交流移動開發的問題, 常見問題還請搜索官方文檔, 我們會不定期更新一些技巧.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章