8、幾行代碼實現一個樹組件【BUI App開發】

這多是最簡單的一棵樹了.html

樹菜單效果圖預覽

file

分析交互

這棵樹的交互像已有的哪一個組件? 摺疊菜單? 點擊顯示,點擊隱藏. 只是摺疊菜單隻有一層, 樹有無限層. ajax

摺疊菜單效果預覽數組

file

BUI的組件都是隻定義了交互, 其它給予了比較大的想象空間. 好比: 摺疊面板, 新聞詳情的查看更多dom

摺疊面板效果異步

file

新聞詳情的查看更多效果組件化

file

樹的實現

若是摺疊菜單進行多層嵌套, 理論上就能夠實現樹的效果, 再把圖標進行修改, 就是咱們要的了. 測試

摺疊面板結構ui

<dl id="uiAccordion" class="bui-accoridon">
    <dt>菜單1</dt>
    <dd>內容1</dd>
    <dt>菜單2</dt>
    <dd>內容2</dd>
</dl>

結構進行嵌套.this

<dl id="uiAccordion" class="bui-accoridon">
    <dt>菜單1</dt>
    <dd>
        <dl class="bui-accoridon">
            <dt>菜單1-1</dt>
            <dd>內容1</dd>
            <dt>菜單1-2</dt>
            <dd>內容2</dd>
        </dl>
    </dd>
    <dt>菜單2</dt>
    <dd>內容2</dd>
</dl>
// 初始化代碼無需修改
var uiAccordion = bui.accordion({
    id: "#uiAccordion"
})

通過測試是可行的, 那這個再把它組件化, 組件化的目的是爲了更簡單方便的複用.url

組件化

這裏結合store進行數據綁定. 修改後的樣式結構.

新建html文件 pages/components/tree/index.html

<style>
    .bui-tree .bui-accordion{
        border-top: 0;
        border-bottom: 0;
        padding-left: .2rem;
    }
    .bui-tree .bui-accordion dd{
        padding-left: .3rem;
    }
    .bui-tree .bui-accordion dt:last-child{
        border-bottom: 0;
    }
    .bui-tree .bui-accordion dd{
        border-top: 0;
    }
    .bui-tree .bui-accordion dd:last-child{
        border-bottom: 0;
    }
    .bui-tree .bui-btn .icon-nosubmenu ,
    .bui-tree .bui-btn .icon-accordion {
        margin-right: .2rem;
    }
    .bui-tree .bui-btn > .icon-accordion:before{
        content:"\e61e"
    }
    .bui-tree .active > .icon-accordion:before{
        content:"\e620"
    }
</style>
<dl class="bui-accordion bui-tree" b-template="tree.tplTrees(tree.trees)">
    <!-- 保留原有的結構註釋, 便於模板理解 
        <dt class="bui-btn bui-box">
        <div class="span1">摺疊菜單</div>
        <i class="icon-accordion"></i>
    </dt>
    <dd>
        摺疊菜單內容
    </dd> -->
</dl>

新建一個js文件 pages/components/tree/index.js

// 組件化必須加上 loader.define
loader.define(function(require, exports, module) {

    // 假設樹的數據層級結構是這樣, 如下是模擬數據
    var data = [
        {id: 1, name: "辦公管理", pid: 0 ,
            children:[
                { id: 2, name: "請假申請", pid: 1,
                    children:[
                        { id: 4, name: "請假記錄", pid: 2 },
                    ],
                },
                { id: 3, name: "出差申請", pid: 1},
            ]
        },
        {id: 5, name: "系統設置", pid: 0 ,
            children:[
                { id: 6, name: "權限管理", pid: 5,
                    children:[
                        { id: 7, name: "用戶角色", pid: 6 },
                        { id: 8, name: "菜單設置", pid: 6 },
                    ]
                },
            ]
        },
    ]

    // 初始化數據行爲存儲, 接收外部參數的 data數組, 若是沒有則展現默認數據, mounted裏面只是初始化了一次accordion, 但本來的id,換成了 `#${module.id} .bui-accordion` , module.id是外部component標籤的id, 沒有會自動生成. 

    // 注意: module.props 是1.6.3的用法,能夠使用 var props = bui.history.getPageParams(module.id) 代替.
    var bs = bui.store({
        el: `#${module.id}`,
        scope: "tree",
        data: {
           trees: module.props && module.props.data || data,
        },
        methods: {},
        templates: {
            tplTrees: function (data,pclass) {
                var html="";

                data.forEach((item, index) => {
                    let hasChildren=item&&item.children&&item.children.length;
                    // 是否有下一級圖標
                    let hasChildrenIcon=hasChildren? `<i class="icon-accordion"></i>`:`<i class="icon-nosubmenu">&#xe620;</i>`;

                    // 沒有下一級展現向右的箭頭
                    let hasChildrenNext=hasChildren? ``:`<i class="icon-listright"></i>`;

                    // 不一樣層級加上父級樣式
                    let level= (pclass||"bui-tree-level") + `-${index}`;

                    html+=`<dt class="bui-btn bui-box ${level}">
                                ${hasChildrenIcon}
                                <div class="span1">${item.name}</div>
                            </dt>`

                    // 若是有子集菜單繼續遞歸生成
                    if (hasChildren) {
                        html+=`<dd class="${level}"><dl class="bui-accordion">`;
                        html+=this.tplTrees(item.children,level);
                        html+=`</dl></dd>`;
                    }

                });
                
                return html;
            }
        },
        mounted: function () {
            // 初始化摺疊插件
            var uiAccordion = bui.accordion({
                id: `#${module.id} .bui-accordion`,
                callback: function (e) {
                    // 點擊的時候觸發了一次click事件, 若是外部有訂閱這個事件,就會被觸發. 
                    loader.trigger(`${module.id}:click`,e)
                }
            });
        }
    })

    return bs;
})

組件的預覽

bui的組件是能夠實時預覽的, 直接打開 index.html#pages/components/tree/index 就能夠預覽當前組件效果, 加上?data=xxx能夠傳組件須要的參數進行模擬, 沒有則使用默認數據;

file

組件的使用

<div class="bui-page bui-box-vertical">
    <header>
        <div class="bui-bar">
            <div class="bui-bar-left">
                <a class="bui-btn btn-back"><i class="icon-back"></i></a>
            </div>
            <div class="bui-bar-main">樹菜單</div>
            <div class="bui-bar-right">
            </div>
        </div>
    </header>
    <main>
        /* 這類組件的數據通常是經過異步請求後而來, 因此不能直接寫在屬性上 */
        <component id="tree" name="pages/components/tree/index" delay="true"></component>
    </main>
</div>
// 模擬請求
bui.ajax({
    url:""
}).then(function(result){
    // 假設樹的數據在 result.data
    // 加載樹組件
    loader.delay({
        id:"tree",
        param: {
            data:result.data
        }
    })
})

監聽樹點擊事件

loader.on("tree:click",function(e){
    // e 爲 loader.trigger 傳過來的參數. 能夠經過 e.target 知道當前點擊的是哪一個dom
    console.log(e.target);
})

更多使用, 請查看組件章節.

最終效果:

file

相關文章
相關標籤/搜索