BUI Webapp 跨平臺框架 1.6 新版功能盤點

BUI是什麼?

BUI 是用來快速構建界面交互的漸進式UI框架, 專一webapp開發, 開發者只需關注業務的開發, 界面的佈局及交互交給BUI, 開發出來的應用, 能夠嵌入平臺 ( 微信公衆號, 微信小程序webview, 聆客, 釘釘, 淘寶, 支付寶等 ), 亦能夠跟其它第三方平臺打包成獨立應用( Bingotouch , Cordova , Dcloud , APICloud , Appcan 等), 最終能夠全跨平臺展現. (包括Ipad)

結合BUI提供的BUI-Fast編輯插件, NPM工具, BUI更是一個移動快速開發的解決方案. 能夠解決如下常見問題.php

  • 移動端的適配兼容問題 (ui)
  • 交互體驗不統一問題 (ui)
  • 複雜交互的控件衝突問題 (ui)
  • 多人協做問題 (模塊化)
  • 微信開發的緩存問題 (模塊化)
  • 後退刷新問題 (單頁路由)
  • 後退多層問題 (單頁路由)
  • 調試數據跨域問題 (npm)
  • 本地服務器架設問題 (npm)
  • 腳本編譯問題 (npm)
  • 打包安全問題 (npm)
  • 同步刷新問題 (npm)
  • 重複安裝依賴 (npm)
  • 開發效率問題 (bui-fast)
  • 使用規範問題 (bui-fast)

適合開發者

  • 後臺開發者(php,java,.net)
  • 前端開發者
  • 美工
  • jquery開發者
  • vue開發者
  • 安卓開發者
  • IOS開發者

developer.png

1. BUI框架新功能-組件化

什麼是組件化呢?

組件化是指解耦複雜系統時將多個功能模塊拆分、重組的過程,有多種屬性、狀態反映其內部特性。css

1.1 單頁組件

在BUI 1.6版本之前有沒有組件化呢?

先來看看組件包含什麼, 模板, 模塊, 樣式, 數據四個部分, BUI一直有組件化, 單頁就是一個組件, 一個單頁由一個同名html(包含樣式),js組成. 移動開發因爲頁面較小, 把一個頁面當作是一個大的組件, 組件裏面會結合多個控件, 比方選項卡,輪播圖,列表刷新等. html

比方下面例子:前端

list.jpg

bui.load({
    url:"pages/list/index.html"
})

跳轉到列表頁面, 咱們即可知道該目錄下還有 pages/list/index.js 文件來處理業務, 默認的模塊名爲pages/list/index. 最簡單的路由, 一切無需配置.vue

pages/list/index.htmljava

<div class="bui-page bui-box-vertical">
    <header></header>
    <main>
        <!-- 輪播圖 -->
        <div id="slide" class="bui-slide"></div>
    </main>
    <footer></footer>
</div>

pages/list/index.jsnode

loader.define(function(require,export,module){
    // 業務代碼
    var pageview = {
        init: function(){
            // 輪播圖控件初始化
            var uiSlide = bui.slide({
                id:"#slide",
                height: 300,
                data: [{
                    image:"images/slide01.jpg"
                },{
                    image:"images/slide02.jpg"
                }]
            })
        }
    }
    // 頁面跳轉便執行
    pageview.init();
    return pageview;
})

路由跳轉內部作了什麼?jquery

// 加載模板
loader.import("pages/list/index.html",function(res){
    // id 指向動態建立的路由頁面id
    $("#id").html(res);
    // 執行js模塊, 若是該模塊沒有被建立過, 會自動執行
    loader.require("pages/list/index")
})
只是簡單示例說明, 實際作了更多複雜的處理. 單頁的開發模塊裏面, $選擇器要替換成 router.$ 選擇器, 若是頁面重複被加載進來, $document查找會致使找到多個相同ID, router.$ 則限制了只在當前頁面.

1.2 控件組件化

隨着業務的深刻, 單頁組件裏面承載了較多業務邏輯, 很差維護. 上面的例子咱們看到, pages/list/index模塊裏面, 初始化了一個控件, 一個頁面若是隻有一個控件, 那也沒什麼, 但每每不止這些, 咱們可能頁面還有TAB, 每一個TAB裏面就有一個輪播圖組件, 那咱們就要區分不一樣的ID初始化不一樣的輪播圖了. 若是把輪播圖抽離成一個單獨的組件, 這部分業務就能夠抽離出來.

定義一個輪播圖組件

咱們新建了一個目錄 components 用來存放這些抽離的組件.git

輪播圖模板
pages/components/slide/index.htmlgithub

<div class="bui-slide"></div>

id="slide" 這個屬性咱們去掉了,若是模板包含id,意味着建立出來的組件會有多個相同id.

輪播圖組件定義
pages/components/slide/index.js

loader.define(function(require,export,module){
    // 接收`component` 標籤上的屬性參數
    var params = bui.history.getParams(module.id);
    // 輪播圖控件初始化
    var uiSlide = bui.slide({
        // 經過父層的id 找到當前的 bui-slide
        id:`#${module.id} .bui-slide`,
        height: 300,
        data: [{
            image:"images/slide01.jpg"
        },{
            image:"images/slide02.jpg"
        }]
    })
    return uiSlide;
})

輪播圖組件加載, component標籤若是無id屬性, 會自動建立一個隨機guid, 也就是組件內部獲取到的 module.id

pages/list/index.html

<div class="bui-page bui-box-vertical">
    <header></header>
    <main>
        <!-- 新聞輪播圖 type 爲自定義屬性,用於區分不一樣數據 --> 
        <component name="pages/components/slide/index" type="news"></component>
        <!-- 視頻輪播圖 --> 
        <component name="pages/components/slide/index" type="video"></component>
    </main>
    <footer></footer>
</div>

輪播圖樣式定義

樣式沒有獨立的做用域, 要防止跟其它樣式衝突, 那組件須要一個獨立的樣式名.
<style>
    .slide-skin .bui-slide-main {}
</style>
<div class="bui-slide slide-skin"></div>
組件包含數據,以確保該組件能正常運行, 咱們能夠把輪播圖的組件再進行優化.

抽離輪播圖測試數據, 示例數據
pages/components/slide/index.json

[{
    image:"images/slide01.jpg"
},{
    image:"images/slide02.jpg"
}]

完整的輪播圖組件
pages/components/slide/index.js

loader.define(function(require,export,module){
    // 接收`component` 標籤上的屬性參數
    var params = bui.history.getParams(module.id);
    // 輪播圖控件初始化
    var uiSlide = bui.slide({
        // 經過父層的id 找到當前的 bui-slide
        id:`#${module.id} .bui-slide`,
        height: 300,
        data: []
    })
    // 經過不一樣參數請求區分不一樣數據
    bui.ajax({
        // 模塊在被加載或者被移到其它路徑下, 都不會影響到這個路徑的地址.
        url:`${module.path}/index.json`,
        data:{
            // 請求接口的不一樣類型
            type: params.type
        },
        success: function(res){
            // 修改輪播圖數據
            uiSlide.option("data",res);
        }
    })
    return uiSlide;
})

測試組件是否正確

組件預覽:
地址欄上輸入如下地址即可預覽組件效果.
index.html#pages/components/slide/index

模擬屬性傳參

在地址上加上參數
index.html#pages/components/slide/index?type=news

2. BUI框架新功能-組件層

BUI 組件有3種表現形式, 路由的跳轉是頁面組件, component標籤加載是一種局部組件, bui.page 是彈出加載組件, 層級最高.

tab.png

比方: 點擊個人, 須要在當前頁插入一個登陸頁面.

login.png

pages/main/main.js

loader.define(function(require,export,module){
    var pageveiw = {
        init: function(){
            // 初始化
            this.tab = this.tabInit();
        },
        isLogin: false,
        pageLogin: null,
        tabInit: function(){
            var that = this;

            var tab = bui.tab({
                id: "#tab"
            });

            // tab 的滑動,點擊,都會觸發 to 事件.
            tab.on("to",function(){
                var index = this.index();
                // 若是跳轉到第3個,而且未登陸, 則插入登陸頁.
                if( index === 3 && !that.isLogin ){
                    if( that.pageLogin ){
                        // 第二次打開就好
                        that.pageLogin.open();
                        return;
                    }
                    // 第一次初始化
                    that.pageLogin = bui.page({
                        url:"pages/login/index.html",
                        // 告訴登陸頁, 是從tab的第三個跳轉過去的, 那登陸回來之後就能夠再跳轉到第三個Tab.
                        param: {
                            type: "tab",
                            index: 3
                        }
                    })
                }
            })

            return tab;
        }
    }
    // 初始化
    pageveiw.init();
    return pageview;
})

pages/login/index.js

loader.define(function(require,export,module){
    var parasm = bui.history.getParams(module.id);
    var pageview = {
        init: function(){
            this.bind();
        },
        bind: function(){
            router.$("#btnLogin").click(function(){
                // 檢測登陸是否成功, 是則跳轉回上一個頁面, 而且觸發to事件

                // 主動關閉
                // var dialog = bui.history.getPageDialog(module.id);
                // dialog.close();

                bui.back(function(mod){
                    // 關閉彈窗
                    mod.pageLogin && mod.pageLogin.close();
                    // 修改登陸狀態
                    mod.isLogin = true;
                    // 拿到上一個模塊,調用tab實例的to方法, 跳到第3各索引, 觸發 監聽的on事件. 
                    mod.tab.to(parasm.index)
                })
            })
        }
    }
    // 初始化
    pageview.init();
    return pageview;
})

做爲登陸頁面組件, 就須要處理多種類型, 比方從路由跳轉的, 比方以組件層的方式加載的, 那分別要作什麼事情?

這個登陸的完整示例工程能夠在 BUI的3種權限登陸 裏面找到. tablogin2 工程.

3. BUI框架新功能-實例分發

實例分發實際上是 bui.store的一個 mixins參數, 這個跟 vue的混入是同樣的. 適合處理比較複雜的頁面, 把模塊分發出去, 便於維護, 跟組件是同樣的道理, 但這個是分離的.

3.1 實例分發

比方有個詳情頁面, 詳情裏面有表單, 正文, 附件.

view.png

這裏咱們使用 bui.store來實現. 案例的預覽地址 實例分發

詳情模板
pages/detail/index.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>
        <ul id="floorNav" class="bui-nav bui-nav-skin01">
            <li class="bui-btn active">表單</li>
            <li class="bui-btn">正文</li>
            <li class="bui-btn">附件(2)</li>
        </ul>
    </header>
    <main>
        <div id="floor" class="bui-floor">
            <div class="bui-floor-main container-y">
                <div class="panel-list bui-interval">
                    <!-- 表單 -->
                    <view name="pages/store/views/form/index"></view>
                    <!-- 正文 -->
                    <view name="pages/store/views/article/index"></view>
                    <!-- 附件 -->
                    <view name="pages/store/views/attach/index"></view>
                </div>
            </div>
            <div class="bui-floor-foot"></div>
        </div>
    </main>
</div>

詳情模塊
pages/detail/index.js

loader.define([
        "pages/store/views/form/index",
        "pages/store/views/article/index",
        "pages/store/views/attach/index"
    ],
    function(form, article, attach, require, exports, module) {

    // 初始化數據行爲存儲
    var bs = bui.store({
        el: ".bui-page",
        scope: "page",
        data: {
            title: "測試標題"
        },
        mixins: [form, article, attach],
        methods: {},
        watch: {},
        computed: {},
        templates: {},
        beforeMount: function() {
            // 數據解析前執行, 修改data的數據示例
            // this.$data.a = 2
        },
        mounted: function() {
            var that = this;
            // 數據解析後執行
            var floor = bui.floor({
                id: "#floor",
                menu: "#floorNav",
                floorItem: "view"
            })
        }
    })

    return bs;
})

表單模板:
pages/store/views/form/index.html

<style>
    .panel-form .bui-list .bui-btn {
        border-bottom: 0;
    }
</style>
<div class="bui-panel panel-form bui-floor-item">
    <div class="bui-panel-head" name="page">表單</div>
    <div class="bui-panel-main container-xy" text="page" b-template="page.tplForm(page.formData)">

    </div>
</div>

表單模塊:
pages/store/views/form/index.js

loader.define(function(require,exports,module) {
    // 在這裏初始化控件
    var pageview = {
        data: {
          formData: {
              title:"《廣州XXX2020年年中預算審批》",
              phone: "13800138000"
          }
        },
        methods: {
          callhim: function(phone){
            // 打電話
            bui.unit.tel(phone);
          }
        },
        templates: {
          tplForm: function(data) {
              var html = "";
              html += `<ul class="bui-list list-form">
                <li class="bui-btn clearactive bui-box-align-top">
                    <label class="bui-label">標題</label>
                    <div class="span1">
                        <div class="bui-value">${data.title}</div>
                    </div>
                </li>
                <li class="bui-btn clearactive bui-box-align-top">
                    <label class="bui-label">電話</label>
                    <div class="span1">
                        <div class="bui-value phone" b-click="page.callhim2(${data.phone})">
                            <b>${data.phone}</b><i class="icon-phone"></i>
                        </div>
                    </div>
                </li>
                ...
            </ul>`;
              return html;
          }
        },
        mounted: function(param) {
            console.log("mounted form")
        }
    };

    // 拋出模塊
    return pageview;
})

其它組件相似, 返回一個對象, 最終在詳情的實例上合併. 這種分發只是業務的拆分, 並沒有獨立做用域. 若是須要獨立做用域, 則應該改成如下加載.

3.2 獨立做用域

詳情模板
pages/detail/index.html

<div class="bui-page bui-box-vertical">
    <header>
        ...
    </header>
    <main>
        <div id="floor" class="bui-floor">
            <div class="bui-floor-main container-y">
                <div class="panel-list bui-interval">
                    <!-- 表單 -->
                    <component name="pages/store/views/form/index"></component>
                    <!-- 正文 -->
                    <view name="pages/store/views/article/index"></view>
                    <!-- 附件 -->
                    <view name="pages/store/views/attach/index"></view>
                </div>
            </div>
            <div class="bui-floor-foot"></div>
        </div>
    </main>
</div>

詳情模塊
pages/detail/index.js

loader.define([
        "pages/store/views/article/index",
        "pages/store/views/attach/index"
    ],
    function(article, attach, require, exports, module) {

    // 初始化數據行爲存儲
    var bs = bui.store({
        el: ".bui-page",
        scope: "page",
        data: {
            title: "測試標題"
        },
        mixins: [article, attach],
        methods: {},
        watch: {},
        computed: {},
        templates: {},
        beforeMount: function() {
            // 數據解析前執行, 修改data的數據示例
            // this.$data.a = 2
        },
        mounted: function() {
            var that = this;
            // 數據解析後執行
            var floor = bui.floor({
                id: "#floor",
                menu: "#floorNav",
                floorItem: "view"
            })
        }
    })

    return bs;
})

表單模板:
pages/store/views/form/index.html

scope改成了form

<style>
    .panel-form .bui-list .bui-btn {
        border-bottom: 0;
    }
</style>
<div class="bui-panel panel-form bui-floor-item">
    <div class="bui-panel-head" name="page">表單</div>
    <div class="bui-panel-main container-xy" text="page" b-template="form.tplForm(form.formData)">

    </div>
</div>

表單模塊
pages/store/views/form/index.js

loader.define(function(require,exports,module) {
    // 在這裏初始化控件
    var bs = bui.store({
        el: `#${module.id}`,
        scope: "form",
        data: {
          formData: {
              title:"《廣州XXX2020年年中預算審批》",
              phone: "13800138000"
          }
        },
        methods: {
          callhim: function(phone){
            // 打電話
            bui.unit.tel(phone);
          }
        },
        templates: {
          tplForm: function(data) {
              var html = "";
              html += `<ul class="bui-list list-form">
                <li class="bui-btn clearactive bui-box-align-top">
                    <label class="bui-label">標題</label>
                    <div class="span1">
                        <div class="bui-value">${data.title}</div>
                    </div>
                </li>
                ...
            </ul>`;
              return html;
          }
        },
        mounted: function(param) {
            console.log("mounted form")
        }
    });

    // 拋出模塊
    return bs;
})

4. BUI框架新功能-歷史記錄

在使用單頁路由初始化之後, 咱們便有了一個歷史記錄 router.history, 新版1.6之後, 把 router.history 抽離出來, 經過 bui.history去訪問. 這樣不管是單頁開發, 仍是多頁開發, 都能經過 bui.history 去獲取實例及參數. 而且在這個對象裏面, 頁面傳參,組件傳參,page傳參, 均可以在這個歷史記錄裏面獲取到之間的依賴關係.

組件的加載是一條線, 線的末端能夠操控線的前端.

var allHistory = bui.history.get();
// allHistory 默認的歷史記錄
[{
    component: {},
    effect: "push",
    exports: {},
    id: "buib7522-dc12-3f33-cdb5-29122a2cf1f6",
    name: "pages/store/view",
    page: {},
    param: {},
    replace: false,
    syncHistory: true,
    toggle: null,
    url: "pages/store/view.html"
}]

4.1 多頁開發

pages/detail/index.html

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="utf-8">
        <title>BUI多頁開發示例</title>
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/buijs/lib/latest/bui.css">
    </head>
    <body>
        <div class="bui-page bui-box-vertical">
            <header>
                <div class="bui-bar">
                    <div class="bui-bar-left">
                        <div class="bui-btn" onclick="bui.back();"><i class="icon-back"></i></div>
                    </div>
                    <div class="bui-bar-main">
                        多頁加載組件
                    </div>
                    <div class="bui-bar-right">
                    </div>
                </div>
            </header>
            <main>
                <!-- 加載輪播圖組件 -->
                <component name="pages/components/slide/index"></component>
            </main>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/buijs/lib/zepto.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/buijs/lib/latest/bui.js"></script>
        <script src="index.js"></script>
    </body>
</html>

多頁的初始化
pages/detail/index.js

bui.ready(function(){
    // 初始化
    var allHistory = bui.history.getLast();
    // 多頁開發的歷史記錄, 永遠只有一個. 頁面跟頁面之間沒法交互, 可是頁面跟組件跟組件層之間的交互是沒問題的. 
})

4.2 單頁開發

pages/detail/index.html

<div class="bui-page bui-box-vertical">
    <header>
        <div class="bui-bar">
            <div class="bui-bar-left">
                <div class="bui-btn" onclick="bui.back();"><i class="icon-back"></i></div>
            </div>
            <div class="bui-bar-main">
                單頁加載組件
            </div>
            <div class="bui-bar-right">
            </div>
        </div>
    </header>
    <main>
        <!-- 加載輪播圖組件 -->
        <component name="pages/components/slide/index"></component>
    </main>
</div>

pages/detail/index.js

loader.define(function(require,export,module){
    // 獲取最後一條歷史記錄
    var currentHistory = bui.history.getLast();
    
})

同樣的組件代碼, 除了腳本模塊的定義不一樣之外. 多頁簡單, 單頁則在體驗,跟操控上會有更多靈活空間. 能夠根據須要自行選擇.

5. buijs-cli 工具

推薦從新安裝 buijs cli工具. 記得關閉360等一切會阻止C盤寫入的程序.
npm install -g buijs

5.1 新增建立案例的命令

buijs-create-case.gif

// 所有權限示例
buijs create -t case-indexlogin

// 部分權限示例
buijs create -t case-tablogin

// 163的組件化示例
buijs create -t case-163

更多登陸案例

5.2 新版的模板源默認更新爲 gitee, 國內構建的速度會快不少.

5.3 新增根據node版本,自動建立對應的工程文件.

5.4 建立app的工做空間, 無需每次都安裝依賴, 具體教程請查看說明文件.

6. bui-fast 編輯器插件

結合新版出了一些快速書寫, 建議更新, 若是使用 vscode只需在插件搜索 bui-fast即可.

7. 其它一些控件的修復及新增

新增了一些方法及控件, 其它更新了控件的一些問題, 就不一一列舉了, 感興趣能夠看看官網的changelog

訂閱號

buishensu.png

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

相關文章
相關標籤/搜索