迷你MVVM框架 avalonjs 學習教程十二、數據聯動

在許多表單應用,咱們常常遇到點擊一個複選框(或下拉框)會引起旁邊的複選框(或下拉框)發生改變,這種聯動效果用avalon來作是很是簡單的。在avalon裏,存在各類綁定回調與$watch回調,徹底知足你的需求。javascript

下面是avalon全部綁定回調。html

  1. data-duplex-changed,用於ms-duplex綁定,值改變後觸發; 參數:當前元素的值
  2. data-include-loaded,用於ms-include-src綁定,模板加載後觸發,能夠在這裏修改模板 參數: tmpl,vmodel1, vmodel2 ...
  3. data-include-rendered,用於ms-include, ms-include-src綁定,模板渲染好後觸發; 沒參數
  4. data-repeat-rendered,用ms-repeat綁定,當監控數組發生添加,刪除,重排等操做時觸發; 參數:當前操做名("add","del","index","clear","move")
  5. data-with-sorted,用ms-repeat, ms-with綁定,趕對象渲染以前觸發,要求輸出一個字符串數組,對象的鍵值對會根據它依次輸出; 參數:原對象的全部鍵名構成的數組
  6. data-with-rendered,用ms-with綁定,當目標對象輸出頁面後觸發; 參數:當前操做名("add","del","index","clear","move")
  7. data-each-rendered,用ms-each綁定,當監控數組發生添加,刪除,重排等操做時觸發; 參數:當前操做名("add","del","index","clear","move")

在表單聯動效果中,咱們最經常使用的是data-duplex-change。事不宜遲,咱們先來一個全選非全選例子吧。java

<!DOCTYPE html>
<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <script src="avalon.js"></script>
        <script>
            var model = avalon.define({
                $id: "test",
                data: [{checked: false}, {checked: false}, {checked: false}],
                allchecked: false,
                checkAll: function() {
                    var bool = this.checked
                    model.data.forEach(function(el) {
                        el.checked = bool
                    })
                },
                checkOne: function() {
                    if (!this.checked) {
                        model.allchecked = false
                    } else {//avalon已經爲數組添加了ecma262v5的一些新方法
                        model.allchecked = model.data.every(function(el) {
                            return el.checked
                        })
                    }
                }
            })
        </script>
    </head>
    <body>
        <table ms-controller="test" border="1">
            <tr>
                <td><input type="checkbox" ms-duplex-radio="allchecked" data-duplex-changed="checkAll"/>全選</td>
            </tr>
            <tr ms-repeat="data">
                <td><input type="checkbox"  ms-duplex-radio="el.checked" ms-data-index=$index data-duplex-changed="checkOne"/>xxxxxxxxxxxx</td>
            </tr>
        </table>
    </body>
</html>

enter image description here 咱們仔細分析其源碼,allchecked是用來控制最上面的複選框的打勾狀況,數組中的checked是用來控制下面每一個複選框的下勾狀況。因爲是使用ms-duplex,所以會監聽用戶行爲,當複選框的狀態發生改變時,就會觸發data-duplex-change回調,將當前值傳給回調。但這裏咱們不須要用它的value值,只用它的checked值。最上面的複選框對應的回調是checkAll,它是用來更新數組的每一個元素的checked屬性,所以一個forEach循環賦值就是。下面的複選框對應的checkOne,它們是用來同步最上面的複選框,只要它們有一個爲false上面的複選框就不能打勾,當它們被打勾了,它們就得循環整個數組,檢查是否全部元素都爲true,是纔給上面的checkall屬性置爲true。git

再看用ms-duplex與$watch實現表格排序效果。github

<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge" /> 
        <script src="../avalon.js" ></script>
        <script>
            if (!Date.now) {//fix 舊式IE
                Date.now = function() {
                    return new Date - 0;
                }
            }
            var model = avalon.define({
                $id: "test",
                selected: "name",
                options: ["name", "size", "date"],
                trend: 1,
                data: [
                    {name: "aaa", size: 213, date: Date.now() + 20},
                    {name: "bbb", size: 4576, date:Date.now() - 4},
                    {name: "ccc", size: 563, date: Date.now() - 7},
                    {name: "eee", size: 3713, date: Date.now() + 9},
                    {name: "555", size: 389, date: Date.now() - 20}
                ]
            })
            model.$watch("selected", function(v) {
                var t = parseFloat(model.trend)
                model.data.sort(function(a, b) {
                    if (v === "name") {
                        return t * a[v].localeCompare(b[v])
                    } else {
                        var ret = a[v] > b[v] ? 1 : -1
                        return t * ret
                    }
                })
            })
            model.$watch("trend", function(t) {
                var v = model.selected, t = parseFloat(t)
                model.data.sort(function(a, b) {
                    var ret = a[v] > b[v] ? 1 : -1
                    return t * ret
                })
            })

        </script>
    </head>
    <body ms-controller="test">
        <div style="color:red">
            <p>本例子用於顯示如何作一個簡單的表格排序</p>
            <p>ms-repeat="array"至關於ms-repeat-el="array" </p>
        </div>
        <p>
            <select ms-duplex="selected">
                <option  ms-repeat="options">{{el}}</option>
            </select>
            <select ms-duplex="trend">
                <option value="1">up</option>
                <option value="-1">down</option>
            </select>
        </p>
        <table width="500px" border="1">
            <tbody >
                <tr ms-repeat="data">
                    <td>{{el.name}}</td> <td>{{el.size}}</td> <td>{{el.date}}</td>
                </tr>
            </tbody>
        </table>
    </body>
</html>

enter image description here 當咱們改動下拉框時,會經過ms-duplex同步selected, trend屬性,而selected, trend的值改變時,就會觸發對應的$watch回調,而後經過監控數組的sort方法實現表格排序。從而也能夠看出監控數組與ms-repeat的強大。數組

咱們再來一個文本域與下拉框的聯動例子,它只用到ms-duplex,不過兩個控件都是綁定同一個屬性。ui

<!DOCTYPE html>
<html>
    <head>
        <script src="avalon.js"></script>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script>
            avalon.define({
                $id: "fruit",
                options: ["蘋果", "香蕉", "桃子", "雪梨", "葡萄", "哈蜜瓜", "橙子", "火龍果", "荔技", "黃皮"],
                selected: "桃子"
            })
        </script>
    </head>
    <body ms-controller="fruit">
        <h3>文本域與下拉框的聯動</h3>
        <input  ms-duplex="selected" />
        <select ms-duplex="selected" >
            <option ms-repeat-option="options" ms-value="option" >{{option}}</option>
        </select>
    </body>
</html>

enter image description here

咱們再看一個超級複雜的三級聯動下拉框。this

<!DOCTYPE html>
<html>
    <head>
        <script src="avalon.js"></script>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script>
            var map = {
                "中國": ["江南四大才子", "初唐四傑", "戰國四君子"],
                "日本": ["日本武將", "日本城堡", "幕府時代"],
                "歐美": ["三大騎士團", "三大魔幻小說", "七大奇蹟"],
                "江南四大才子": ["祝枝山", "文徵明", "唐伯虎", "周文賓"],
                "初唐四傑": ["王勃", "楊炯", "盧照鄰", "駱賓王"],
                "戰國四君子": ["楚國春申君黃歇", "齊國孟嘗君田文", "趙國平原君趙勝", "魏國信陵君魏無忌"],
                "日本武將": ["織田信長", "德川家康", "豐臣秀吉"],
                "日本城堡": ["安土城", "熊本城", "大阪城", "姬路城"],
                "幕府時代": ["鎌倉", "室町", "豐臣", "江戶"],
                "三大騎士團": ["聖殿騎士團", "醫院騎士團", "條頓騎士團"],
                "三大魔幻小說": ["冰與火之歌", "時光之輪", "荊刺與白骨之王國"],
                "七大奇蹟": ["埃及胡夫金字塔", "奧林匹亞宙斯巨像", "阿爾忒彌斯月神殿", "摩索拉斯陵墓", "亞歷山大港燈塔", "巴比倫空中花園", "羅德島太陽神巨像"]
            }

            avalon.define("linkage", function(vm) {
                vm.first = ["中國", "日本", "歐美"]
                vm.second = map[vm.first[1]].concat()
                vm.third = map[vm.second[0]].concat()
                vm.firstSelected = "日本"
                vm.secondSelected = "日本武將"
                vm.thirdSelected = "織田信長"

                vm.$watch("firstSelected", function(a) {
                    vm.second = map[a].concat()
                    vm.secondSelected = vm.second[0]
                })
                vm.$watch("secondSelected", function(a) {
                    vm.third = map[a].concat()
                    vm.thirdSelected = vm.third[0]
                })
            })
        </script>
    </head>
    <body >
        <div ms-controller="linkage">
            <h3>下拉框三級聯動</h3>
            <select ms-duplex="firstSelected" >
                <option  ms-repeat="first" ms-value="el" >{{el}}</option>
            </select>
            <select ms-duplex="secondSelected" >
                <option ms-repeat="second" ms-value="el" >{{el}}</option>
            </select>
            <select ms-duplex="thirdSelected" >
                <option ms-repeat="third" ms-value="el" >{{el}}</option>
            </select>
        </div>
    </body>
</html>

enter image description here 因爲存在三個下拉框,須要的數據比較多,所以咱們搞了一個map來存放它們。。而後咱們先初始化第一個下拉框,vm.first = [」中國」, 」日本」, 」歐美」],默認是選中第二個(firstSelected)。而後初始化第二個下拉框,須要從map拷貝一份賦給second,而後再默認其選中項,而後是第三個下拉框……orm

接着是經過$watch回調實現聯動,不用管第三個下拉框(由於它老是被動的),那麼只有監聽firstSelected, secondSelected。每次變化都須要從map找到正確的數組,複製一次賦給second與third,而且默認選中第一項。htm

最後奉上一用戶作的多級聯動效果,本身細細品味吧。

<!DOCTYPE html>
<html lang="zh-cn">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script src="avalon.js"></script>
        <script>

            var data = [
                {"id": 0, "name": "1公司", "grade": -1, "parentid": "-1"},
                {"id": 1, "name": "廣東公司", "grade": 0, "parentid": "0"},
                {"id": 2012300001, "name": "廣州1分公司", "grade": 1, "parentid": 1},
                {"id": 200000000, "name": "廣州分公司", "grade": 1, "parentid": 1},
                {"id": 4050, "name": "天河分公司", "grade": 2, "parentid": 200000000},
                {"id": 999182, "name": "工業園營銷服務中心", "grade": 3, "parentid": 4050},
                {"id": 4174, "name": "南沙分公司", "grade": 2, "parentid": 200000000},
                {"id": 10121, "name": "南沙營銷服務中心", "grade": 3, "parentid": 4174},
            ]
            var a = avalon.define("test", function(vm) {
                vm.searchForm = [];
                vm.setSearchFormInit = function(currNode) {
                    var childNodes = vm.getChildOrg(currNode);
                    if (childNodes.length)
                        vm.searchForm = [childNodes];
                };
                vm.setSearchForm = function(index) {
                    //vm.searchForm._del(index,10)//在選中某個select後,取得index,刪除它後邊的全部成員
                    avalon.log("刪除第" + index + "個元素後的全部成員")
                    a.searchForm.removeAll(function(arr, i) {
                        if (i > index)
                            return true;
                        return false;
                    });
                    var currNode = this.value;
                    var childNodes = vm.getChildOrg(currNode);
                    if (childNodes.length)
                        vm.searchForm.push(childNodes);
                };
                vm.getChildOrg = function(id) {
                    var retList = [];
                    for (var i = 0; i < data.length; i++) {
                        var elem = data[i]
                        if (elem.parentid != id)
                            continue;
                        retList.push({
                            id: elem.id,
                            name: elem.name,
                            parentid: elem.parentid
                        });
                    }
                    return retList;
                }
            })
            a.setSearchFormInit(0)
        </script>
    </head>
    <body ms-controller="test">
        <div ms-repeat-form="searchForm">
            <select ms-change="setSearchForm($index)">
                <option></option>
                <option ms-repeat-el="form" ms-value="el.id">{{el.name}}</option>
            </select>
        </div>
    </body>
</html>

enter image description here

相關文章
相關標籤/搜索