BUI 綜合案例

2020-08-12 14:12 更新

1. 待辦處理

案例

案例截圖

核心思路: 定義了3個(gè)字段.

  • todo 是當(dāng)前已有的數(shù)據(jù), 會(huì)通過(guò) b-template 進(jìn)行渲染.
  • todoText 搜索框的默認(rèn)文本, 如果空則顯示placeholder, 通過(guò) b-model 進(jìn)行關(guān)聯(lián).
  • nextTodoId 這個(gè)是數(shù)據(jù)的自增字段, 不是必須, 可以使用唯一id來(lái)處理.

定義了一個(gè)方法, 通過(guò) b-click 進(jìn)行綁定. 點(diǎn)擊的時(shí)候, 檢驗(yàn)字段是否為空, 不為空則增加一條待辦.

模板里面還通過(guò)b-click 綁定了一個(gè)removeTodo 刪除的方法, 通過(guò)索引刪除, 這里用到一個(gè)動(dòng)態(tài)索引, 這個(gè)是內(nèi)置的, 前面在事件綁定章節(jié)已經(jīng)講過(guò). 有增刪改的數(shù)據(jù), i 拿到的是固定的值.



var bs = bui.store({
    scope: "page", 
    data: {
        todo: [{
            id: 1,
            title: "參加項(xiàng)目會(huì)議"
        },{
            id: 2,
            title: "項(xiàng)目啟動(dòng)會(huì)"
        },{
            id: 3,
            title: "看電影"
        }],
        todoText: "",
        nextTodoId: 4
    },
    methods: {
        addTodo: function (e) {


            if( this.todoText ){
                this.todo.push({
                    id: this.nextTodoId++,
                    title:this.todoText
                })
                this.todoText = "";
            }else{
                bui.hint("請(qǐng)?zhí)顚?xiě)待辦事項(xiàng)")
            }
        },
        removeTodo: function (index) {
            // 方法1: 通過(guò)索引刪除
            this.todo.splice(index,1);
            this.todoText = "";
        }
    },
    templates: {
        tplTodo: function (data) {
            var _self = this;
            var html = "";
            data.forEach(function (item,i) {


                html += `<li id="${item.id}" class="bui-btn bui-box">
                            <div class="span1">${item.title}</div>
                            <i b-click="page.removeTodo($parentIndex)" class="icon-remove large"></i>
                        </li>`;
            })
            return html;
        }
    }
})

核心html

<!-- 搜索條控件結(jié)構(gòu) -->
<div class="bui-searchbar bui-box">
    <div class="span1">
        <div class="bui-input">
            <i class="icon-search"></i>
            <input type="text" value="" placeholder="請(qǐng)輸入待辦" b-model="page.todoText" />
            <div class="bui-btn" b-click="page.addTodo">添加</div>
        </div>
    </div>
</div>
<!-- 數(shù)組todo lendth 改變的時(shí)候,不會(huì)自動(dòng)觸發(fā),需要監(jiān)聽(tīng) page.todo 數(shù)組改變 -->
<div class="section-title">待辦事項(xiàng): <b b-text="page.todo.length"></b></div>
<ul b-template="page.tplTodo(page.todo)" class="bui-list"></ul>

預(yù)覽

查看效果

2. 彈窗選擇交互

如果數(shù)據(jù)一開(kāi)始有值,還需要把值跟模板里的數(shù)據(jù)進(jìn)行比對(duì),處理成選中狀態(tài).

案例

案例截圖

js

var bs = bui.store({
        scope: "page", // 用于區(qū)分公共數(shù)據(jù)及當(dāng)前數(shù)據(jù)的唯一值
        data: {
            items: [{
                id: "guangzhou",
                name: "廣州",
            }, {
                id: "shenzhen",
                name: "深圳",
            }, {
                id: "dongguan",
                name: "東莞",
            }],
            checked: ["shenzhen"], //緩存選中的值, 默認(rèn)選中深圳
            checkedObj: [{
                id: "shenzhen",
                name: "深圳",
            }],
        },
        methods: {
            open: function() {
                this.uiDialog.open();
            }
        },
        watch: {
            checked: function(val) {
                var _self = this;
                // 獲取的使用 this.$data.xxx
                var items = bui.array.getAll(_self.$data.items, val, "id");


                // 替換新的值 this.xxx
                bui.array.replace(this.checkedObj, items);
            }
        },
        computed: {},
        templates: {
            tplItem: function(data) {
                var html = "";


                data.forEach(function(item, i) {
                    html += `<li class="bui-btn" id="${item.id}">${item.name}</li>`
                })


                return html;
            },
            tplCity: function(data) {
                var html = "";
                var _self = this;
                data.forEach(function(item, i) {
                    // 渲染已經(jīng)選擇的城市
                    var hasChoose = _self.checkedObj && bui.array.compare(_self.checkedObj, item.id, "id");
                    var hasChecked = hasChoose ? "checked" : "";
                    html += `<li class="bui-btn bui-box bui-btn-line">
                      <div class="span1">
                          <label for="interest+${i}">${item.name}</label>
                      </div>
                      <input id="interest+${i}" type="checkbox" class="bui-choose" name="interest" value="${item.id}" text="" ${hasChecked} b-model="page.checked">
                  </li>`
                })


                return html;
            }
        },
        mounted: function() {
            // 加載后執(zhí)行


            this.uiDialog = bui.dialog({
                id: "#uiDialog"
            });


        }
    })

注意: checkedObj: null 數(shù)組如果需要通過(guò)this.checkedObj = []賦值操作, 先設(shè)置為空; 如果初始值是數(shù)組, 則需要通過(guò) bui.array.xxx 去操作才會(huì)觸發(fā)界面響應(yīng).

核心html

<div class="bui-page page-store">
    <main>
        <div class="bui-btn" b-click="page.open()">點(diǎn)擊選擇喜歡的城市</div>
        <div class="subtitle">您已選擇:</div>
        <!-- 列表控件 html 對(duì)應(yīng)的結(jié)構(gòu):  -->
        <ul class="bui-list" b-template="page.tplItem(page.checkedObj)"></ul>
    </main>
    <!-- 對(duì)話(huà)框需要在 bui-page 里面, 這樣默認(rèn)才會(huì)解析 b- 行為屬性的值 page.xxx  -->
    <div id="uiDialog" class="bui-dialog">
        <div class="bui-dialog-head">選擇喜歡的城市</div>
        <div class="bui-dialog-main">
          <ul class="bui-list" b-template="page.tplCity(page.items)"></ul>
        </div>
        <div class="bui-dialog-close"><i class="icon-close"></i></div>
    </div>
</div>

預(yù)覽

查看效果

3. 多選聯(lián)動(dòng)復(fù)雜場(chǎng)景

案例

案例截圖

2.1 簡(jiǎn)單思路版

在data設(shè)計(jì)了4個(gè)字段, 分別是:

  • selectA A的數(shù)據(jù)源
  • selectB B的數(shù)據(jù)源
  • selectAChecked A的選中暫存區(qū)
  • selectBChecked B的選中暫存區(qū)

定義了4個(gè)方法:

  • modifyStatusA 點(diǎn)擊以后修改A的激活狀態(tài), 并把數(shù)據(jù)存到A暫存區(qū)
  • modifyStatusB 點(diǎn)擊以后修改B的激活狀態(tài), 并把數(shù)據(jù)存到B暫存區(qū)
  • addToB 合并A的選中數(shù)據(jù)到B的數(shù)據(jù)源里面, 數(shù)據(jù)改變會(huì)自動(dòng)渲染到視圖
  • addToA 合并B的選中數(shù)據(jù)到A的數(shù)據(jù)源里面, 數(shù)據(jù)改變會(huì)自動(dòng)渲染到視圖

操作數(shù)據(jù)便會(huì)更新視圖. 代碼有點(diǎn)多, 但是理清了思路,我們后面再看優(yōu)化版.

var bs = bui.store({
    scope: "page", 
    data: {
        selectAChecked: [], // A區(qū)選中暫存區(qū)
        selectBChecked: [], // B區(qū)選中暫存區(qū)
        selectA: [          // 聯(lián)動(dòng)select的數(shù)據(jù)源
          { text: 'One', value: 'A', selected: false },
          { text: 'Two', value: 'B', selected: false },
          { text: 'Three', value: 'C', selected: false }
        ],
        selectB: [],
    },
    methods: {
        modifyStatusA: function (index) {


            var selectedItem = this.selectA[index],
                selecteds = this.selectAChecked,
                // 判斷是否唯一
                indexs = bui.array.index(this.selectA[index].value,selecteds,"value");


            // 選中暫存區(qū)的增加或減少
            if( indexs > -1 ){
                selecteds.splice(indexs,1);
            }else{
                selecteds.push(selectedItem);
            }


            // 修改選中狀態(tài)
            this.selectA[index].selected = !this.selectA[index].selected;
            // 替換整條數(shù)據(jù)并觸發(fā)數(shù)據(jù)變更
            bui.array.set(this.selectA,index,this.selectA[index]);
        },
        modifyStatusB: function (index) {
            var selectedItem = this.selectB[index],
                selecteds = this.selectBChecked,
                indexs = bui.array.index(this.selectB[index].value,selecteds,"value");


            // 選中暫存區(qū)的增加或減少
            if( indexs > -1 ){
                selecteds.splice(indexs,1);
            }else{
                selecteds.push(selectedItem);
            }


            // 更新字段
            this.selectB[index].selected = !this.selectB[index].selected;
            // 替換整條數(shù)據(jù)并觸發(fā)數(shù)據(jù)變更
            bui.array.set(this.selectB,index,this.selectB[index]);
        },
        addToB: function (e) {
            // 刪除選中狀態(tài)
            this.selectAChecked.forEach(function(item,i){
                item.selected = false;
            })
            // 合并并觸發(fā) this.selectB
            bui.array.merge(this.selectB,this.selectAChecked);
            // 刪除this.selectA選中數(shù)據(jù),通過(guò)value字段比對(duì),支持多個(gè)
            bui.array.remove(this.selectA,this.selectAChecked,"value")


            // 清空A暫存區(qū)數(shù)據(jù)
            bui.array.empty(this.selectAChecked);
        },
        addToA: function (e) {
            // 刪除選中狀態(tài)
            this.selectBChecked.forEach(function(item,i){
                item.selected = false;
            })
            // 合并并觸發(fā) this.selectA
            bui.array.merge(this.selectA,this.selectBChecked);


            // 刪除選中數(shù)據(jù),通過(guò)value字段比對(duì)
            bui.array.remove(this.selectB,this.selectBChecked,"value")
            // 清空B暫存區(qū)數(shù)據(jù)
            bui.array.empty(this.selectBChecked);
        },
    },
    templates: {
        // 聯(lián)動(dòng)的示例,增加了事件綁定
        tplSelectA: function (data,te) {
            var html ='';
            data.forEach(function (item,i) {
                var active = item.selected ? "active" : "";
                html +=`<li b-click='page.modifyStatusA($index)' class="bui-btn ${active}">${item.text}</li>`;
            })
            return html;
        },
        tplSelectB: function (data) {
            var html ='';
            data.forEach(function (item,i) {
                var active = item.selected ? "active" : "";
                html +=`<li b-click='page.modifyStatusB($index)' class="bui-btn ${active}">${item.text}</li>`
            })
            return html;
        }
    }
})

核心的html綁定

<style type="text/css">
    .bui-select .active {
        color: red;
    }
</style>
<div class="bui-box">
    <div class ="span1">
        <h2 class="bui-box"><b b-text="page.selectAChecked.length"></b>/<b b-text="page.selectA.length"></b></h2>
        <div class="bui-select" b-template="page.tplSelectA(page.selectA)">
        </div>
    </div>
    <div style="width: 100px">
        <div class="bui-btn" b-click="page.addToB">添加到B</div>
        <div class="bui-btn" b-click="page.addToA">添加到A</div>
    </div>
    <div class="span1">
        <h2 class="bui-box"><div class="span1">列表2</div><b b-text="page.selectBChecked.length"></b>/<b b-text="page.selectB.length"></b></h2>
        <div class="bui-select" b-template="page.tplSelectB(page.selectB)">
        </div>
    </div>
</div>

預(yù)覽

查看效果

2.2 代碼優(yōu)化版

案例

案例截圖

優(yōu)化了操作流程, 在原來(lái)的data增加多了2個(gè)狀態(tài): 這2個(gè)狀態(tài)都是一個(gè)對(duì)象, 因?yàn)閷?shí)際上想要的是 disabled這個(gè)樣式名, 如果你的樣式上, 是設(shè)計(jì)的 canAdd, canDel 作為樣式名, 只需要布爾值就行.

  • canAdd 是否能夠增加
  • canDel 是否能夠刪除

原先的4個(gè)方法, 優(yōu)化成了2個(gè), 一個(gè)點(diǎn)擊的時(shí)候修改狀態(tài), 一個(gè)是合并數(shù)據(jù).

原先的2個(gè)模板方法, 優(yōu)化成了1個(gè), 通過(guò)傳進(jìn)來(lái)的不同字段進(jìn)行處理就行. 這里要理解,b-click='page.setStatus(${target},$index,${targetChecked})' ${target}$index 的區(qū)別.

注意: b-template 傳過(guò)去的第一個(gè)值會(huì)被解析成數(shù)據(jù), 其它參數(shù)傳什么就是什么.

/**
 * 設(shè)計(jì)思路說(shuō)明:
 * 左邊列表A: selectA
 * 右邊列表B: selectB
 * 左邊選中列表暫存區(qū)A: selectAChecked
 * 右邊選中列表暫存區(qū)B: selectBChecked
 * 點(diǎn)擊列表, 往暫存區(qū)存放對(duì)應(yīng)的數(shù)據(jù), 并且通過(guò)watch 暫存區(qū)的數(shù)據(jù)變更,把按鈕的狀態(tài)變成能夠操作.
 * 點(diǎn)擊按鈕添加到B, 則把右邊列表數(shù)據(jù),合并A選中的暫存區(qū), 并刪除選中狀態(tài), 清空A暫存區(qū)數(shù)據(jù)
 * 點(diǎn)擊按鈕添加到A, 則把左邊列表數(shù)據(jù),合并B選中的暫存區(qū), 并刪除選中狀態(tài), 清空B暫存區(qū)數(shù)據(jù)
 */


var bs = bui.store({
    scope: "page",
    data: {
        canAdd: {
            disabled: true
        },
        canDel: {
            disabled: true
        },
        selectAChecked: [], // A區(qū)選中暫存區(qū)
        selectBChecked: [], // B區(qū)選中暫存區(qū)
        selectA: [
          { text: 'One', value: 'A', selected: false },
          { text: 'Two', value: 'B', selected: false },
          { text: 'Three', value: 'C', selected: false }
        ],
        selectB: [],
    },
    methods: {
        setStatus: function (target,index,checked) {


            var selectedItem = this[target][index],
                selecteds = this[checked],
                // 判斷是否唯一
                indexs = bui.array.index(this[target][index].value,selecteds,"value");


            // 選中暫存區(qū)的增加或減少
            if( indexs > -1 ){
                selecteds.splice(indexs,1);
            }else{
                selecteds.push(selectedItem);
            }


            // 修改選中狀態(tài)
            this[target][index].selected = !this[target][index].selected;
            // 替換第幾條數(shù)據(jù)并觸發(fā)數(shù)據(jù)this[target] 的dom變更
            bui.array.set(this[target],index,this[target][index]);
        },
        moveSelect: function (target,checked,targetB) {


            // 修改按鈕狀態(tài)
            var btn = checked == "selectBChecked" ? "canDel" : "canAdd";


            if( this[btn].disabled ){ return; }


            // 移動(dòng)過(guò)去以后,不需要選中狀態(tài)
            this[checked].forEach(function (item) {
                item.selected = false;
            })


            // 合并并觸發(fā) this.selectB
            bui.array.merge(this[target],this[checked]);


            // 刪除this.selectA選中數(shù)據(jù),通過(guò)value字段比對(duì),支持多個(gè)
            bui.array.delete(this[targetB],this[checked],"value");


            // 清空暫存區(qū)數(shù)據(jù)
            bui.array.empty(this[checked]);
        },
    },
    watch: {
        selectAChecked: function (data) {
            // 修改添加按鈕狀態(tài)
            this.canAdd.disabled = !data.length;
        },
        selectBChecked: function (data) {
            // 修改刪除按鈕狀態(tài)
            this.canDel.disabled = !data.length;
        }
    },
    templates: {
        // 聯(lián)動(dòng)的示例,增加了事件綁定
        tplSelect: function (data,target,targetChecked) {


            var html ='';
            data.forEach(function (item,i) {
                var active = item.selected ? "active" : "";
                // $index 為內(nèi)置的動(dòng)態(tài)索引, i 不一定等于 $index
                html +=`<li b-click='page.setStatus(${target},$index,${targetChecked})' class="bui-btn ${active}">${item.text}</li>`;
            })
            return html;
        }
    }
})

<style type="text/css">
    .bui-select .active {
        color: red;
    }
    .btn-controls {
        width: 1rem;
        margin:0 .1rem;
    }
    .btn-controls .bui-btn{
        margin-top:.1rem;
    }
</style>
<div class="bui-box">
    <div class ="span1">
        <div class="subtitle bui-box">
            <div class="span1">列表1</div>
            <b b-text="page.selectAChecked.length"></b>/<b b-text="page.selectA.length"></b>
        </div>
        <div b-template="page.tplSelectA(page.selectA)" class="bui-list">
        </div>
    </div>
    <div class="btn-controls">
        <!-- 傳多個(gè)數(shù)據(jù)源字段 -->
        <div b-click="page.moveSelect(selectB,selectAChecked,selectA)" b-class="page.canAdd" class="bui-btn round">>></div>
        <div b-click="page.moveSelect(selectA,selectBChecked,selectB)" b-class="page.canDel" class="bui-btn round"><<</div>
    </div>
    <div class="span1">
        <div class="subtitle bui-box">
            <div class="span1">列表2</div>
            <b b-text="page.selectBChecked.length"></b>/<b b-text="page.selectB.length"></b>
        </div>
        <div b-template="page.tplSelectB(page.selectB)" class="bui-list">
        </div>
    </div>
</div>

預(yù)覽

查看效果

4. 動(dòng)態(tài)表單

案例

案例截圖

<div class="bui-page page-store page-input">
    <header>
        <div  lass="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">動(dòng)態(tài)表單</div>
            <div class="bui-bar-right">
            </div>
        </div>
    </header>
    <main>
        <div class="bui-btn" b-click="page.add"><i class="icon-plus"></i>添加</div>
        <div b-template="page.tplUser(page.users)">


        </div>


        <div class="container-xy">
            <button class="bui-btn primary round" b-click="page.submitForm">提交</button>
        </div>
    </main>
</div>

點(diǎn)擊添加會(huì)新增一個(gè)動(dòng)態(tài)表單, 注意 $index 的指向是指向 b-target="ul", 獲得的索引,才是跟數(shù)據(jù)一一對(duì)應(yīng)的.

var bs = bui.store({
    scope: "page", // 用于區(qū)分公共數(shù)據(jù)及當(dāng)前數(shù)據(jù)的唯一值
    data: {
        users: [{
            name: "",
            id: ""
        }],
    },
    methods: {
        submitForm: function(e) {
            console.log(this.users)
            return false;
        },
        add: function() {
            this.users.push({
                name: "",
                id: ""
            })
        },
        remove: function(index) {
            console.log(index)
            bui.array.deleteIndex(this.users, index);
        }
    },
    watch: {},
    computed: {},
    templates: {
        tplUser: function(data) {
            var html = `<ul class="bui-list">`;
            var that = this;
            data.forEach(function(item, index) {
                let length = that.users.length - 1;
                html += `<li class="bui-btn-title bui-box clearactive">表單${length}<div class="span1"></div><div class="bui-btn" b-click="page.remove($index)" b-target="ul"><i class="icon-remove"></i></div></li><li class="bui-btn bui-box clearactive">
                <label class="bui-label">姓名</label>
                <div class="span1">
                    <div class="bui-value"><input type="text" name="fname" b-model="page.$index.name" b-target="ul"></div>
                </div>
            </li>
            <li class="bui-btn bui-box clearactive">
                <label class="bui-label">身份證</label>
                <div class="span1">
                    <div class="bui-value"><input type="text" name="fname" b-model="page.$index.id" b-target="ul"></div>
                </div>
            </li>`
            })
            html += `</ul>`


            return html;
        }
    },
    mounted: function() {
        // 加載后執(zhí)行
    }
})

總結(jié)

數(shù)據(jù)驅(qū)動(dòng)的改變?cè)谟谒悸返霓D(zhuǎn)變, 合理的使用,可以大大的減少手動(dòng)操作dom的代碼. 數(shù)據(jù)驅(qū)動(dòng)不比dom操作, 有可能需要去理解核心的業(yè)務(wù)以后才能上手, 所以在代碼的設(shè)計(jì)數(shù)據(jù)上, 寫(xiě)上自己的設(shè)計(jì)思路, 這對(duì)于后面的維護(hù)會(huì)很有幫助.

bui.store 并不是必須用到的, 使用單頁(yè)及模塊化已經(jīng)可以很好的處理各種問(wèn)題. 只是在一些表單聯(lián)動(dòng)上, 你會(huì)發(fā)現(xiàn)這個(gè)真的很有用!

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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)