使用MVVM框架avalon.js實現一個簡易日歷


      最近在做公司內部的運營管理系統,因為與日歷密切相關,同時無需觸發條件直接顯示在頁面上,所以針對這樣的功能場景,我就用avalon快速實現了一個簡易日歷,畢竟也是第一次造日歷這種輪子,所以這里記錄下我當時的一些思路,一來做一些技術總結,二來也是給像我這樣第一次做日歷的前端工程師一些參考。

      先來一起看下日歷的界面:

      日歷功能包括:1.顯示當前月、上個月后幾天、下個月前幾天的日期,2.切換到上個月,3.切換到下一個月,4.回到今天,5.點擊某天彈出當天的年月日(如2014-10-26),同時不在當前月的日期以更淡的顏色與當前月進行一個區分。

      因為使用avalon進行實現,了解MVVM思想的人都知道,mvvm不操作dom,這是框架內部做的事情,而我們僅僅要做的是操作Mode層,也即數據層。

      這里我用一個數組存儲當前一個月的所有日期對象,每一天就是一個對象,這個對象包括年,月,日,時間戳,是否隸屬於當前月等。如下所示:

var caleadar = [
    {
        year : 2014,          // 年份
        month : 10,           // 月份
        date : 1,             //
        time : 1414771200000, // 時間戳
        flag : false          // 是否隸屬於當前月
    },
    {
        year : 2014,
        month : 10,
        date : 2,
        time : 1414911123564,
        flag : true
    },
    .....
];

      得到這樣一個保存當前月所有信息的數組之后,因為此時caleadar是一個一維數組,而日歷是每7天一行,所以這里要將caleadar轉化為一個二維數組,每一個子數組里面保存的是一周的日期信息,這樣就可以利用avalon的動態模板引擎進行雙重模板渲染,這樣一個日歷就出來了。

      利用getWeeks函數我們就可以得到存儲有當前月所有日期信息的數組,如下:

function getWeeks(ooo) {
    var dateObj = new Date();
    var year = ooo.getFullYear();
    var month = ooo.getMonth(); //得到今天是幾月(0 ~ 11)
    var date = ooo.getDate(); //得到今天是幾號 (1 ~ 31)
    //var cur = new Date(year, month, date);
    var cur = new Date(year, month, 1);
    cur.setMonth(month + 1); //改為下一個月,
    cur.setDate(0);//由於日期是1 ~ 31, 0則是退到上一個月的最后一天,於是得到這個月的總天數
    var num = cur.getDate();
    var next = 6 - cur.getDay();
    var dates = avalon.range(1, num + 1);
    dates = dates.map(function(d) {
        return dateObj.getFullYear() === year &&
            dateObj.getMonth() === month &&
            dateObj.getDate() === d ? {
            year: year,
            month: month,
            date: d,
            isToday: true,
            flag: true,
            time: new Date(year, month, d) - 0
        } : {
            year: year,
            month: month,
            date: d,
            flag: true,
            time: new Date(year, month, d) - 0
        };
    });
    cur.setMonth(month);
    cur.setDate(1); //得到當月的第一天
    var prev = cur.getDay(); //0 ~ 6
    cur.setDate(date); //還原
    //補上上一個月的日期
    if (month - 1 < 0) {
        year--;
        month = 11;
        for (var i = 0; i < prev; i++) {
            var curr = new Date(year, month, -1 * i);
            dates.unshift({
                year: year,
                month: month,
                date: curr.getDate() + 1,
                flag: false,
                time: curr - 0
            })
        }
    } else {
        for (i = 0; i < prev; i++) {
            curr = new Date(year, month, -1 * i);
            dates.unshift({
                year: year,
                month: month - 1,
                date: curr.getDate(),
                flag: false,
                time: curr - 0
            })
        }
    }
    //補上下一個月的日期
    if (month + 1 == 12) {
        year++;
        month = 0;
        for (i = 0; i < next; i++) {
            curr = new Date(year, month, i + 1);
            dates.push({
                year: year,
                month: month,
                date: curr.getDate(),
                flag: false,
                time: curr - 0
            })
        }
    } else {
        for (i = 0; i < next; i++) {
            curr = new Date(year, month + 1, i + 1);
            dates.push({
                year: year,
                month: month + 1,
                date: curr.getDate(),
                flag: false,
                time: curr - 0
            })
        }
    }
    var ret = [];
    while (dates.length) {//每行七個分組
        ret.push(dates.splice(0, 7));
    }

    return ret; //一個二維數組
}

      這里ooo是getWeeks的唯一參數,它是一個Date對象。

      獲取到數據之后,直接在html里面進行數據渲染,日歷就出來了,相關日歷html如下:

<div class="game_calendar" ms-controller="caleadarID">
    <div class="current_info">
        <button type="button" ms-click="backToToday">today</button>
        <button type="button" ms-click="prevMonth">prev</button>
        <button type="button" ms-click="nextMonth">next</button>
        <span>{{cyear}}年{{cmonth + 1}}月</span>
    </div>
    <table width="100%" border="0" cellspacing="0" cellpadding="0" class="week_title">
        <tbody>
        <tr valign="bottom">
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        </tbody>
    </table>
    <table width="100%" cellpadding="0" cellspacing="1" class="calendar_main">
        <tbody>
        <tr ms-repeat-el="calendar">
            <td ms-class="day_style:elem.flag==true" valign="top" ms-repeat-elem="el" ms-click="alert(elem)">
                <div class="day_mouse">
                    <div class="day_no" ms-if="elem.isToday!=true">{{elem.date}}</div>
                    <div class="day_no" ms-class="today:elem.isToday==true" ms-if="elem.isToday==true">今天</div>
                </div>
            </td>
        </tr>
        </tbody>
    </table>
</div>

      我們可以看到,模板里面運用了大量的以ms-開頭的綁定屬性和{{}}插值表達式,有的是用來渲染樣式,有的是用來綁定事件。這樣,一個日歷就出來了。

      接下來就是日歷的切換功能了,實際上上面三個功能本質都是一樣,只要傳入getWeeks的參數不同返回不同的數組信息就行。因此在程序初始化是我們先保存幾個變量,如下:

var dateObj = new Date();
vm.calendar = _private.getWeeks(dateObj); //存儲當月日歷
vm.cyear = dateObj.getFullYear();  //當前年份
vm.cmonth = dateObj.getMonth();   //當前月份
vm.cdate = dateObj.getDate();     //當前日

      接下來就是相關處理邏輯:

//上一個月
vm.prevMonth = function () {
    vm.cdate = 1;
    --vm.cmonth;
    if (vm.cmonth < 0) {
        vm.cyear--;
        vm.cmonth = 11;
    }
    _private.change();
};

//下一個月
vm.nextMonth = function () {
    vm.cdate = 1;
    ++vm.cmonth;
    if (vm.cmonth == 12) {
        vm.cyear++;
        vm.cmonth = 0;
    }
    _private.change();
};

//回到今天
vm.backToToday = function () {
    var dateObj = new Date();
    vm.cyear = dateObj.getFullYear();
    vm.cmonth = dateObj.getMonth();
    vm.cdate = dateObj.getDate();
    _private.change();
};

      改變當前年、月、日后,我們只需要調用change函數來改變caleadar數組,change函數如下:

vm.caleader = _private.getWeeks(new Date(vm.cyear, vm.cmonth, vm.cdate));

      這樣,一個簡易日歷就實現了,從頭到尾,我們沒有操作一行dom,完全的model操作,是不是很爽?

      這里為了讓大家看到更好的日歷效果,附上日歷源碼,歡迎下載,有任何疑問歡迎留言!

      caleadar.zip


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM