zoukankan      html  css  js  c++  java
  • MUI开发记录——我的考勤

    已经好久没有更新技术博客了,因为最近一直在做跨平台web app应用的开发,由于是刚做这个,也没太多经验同大家分享,可我是一个闲不住的人,我还是决定于百忙之中抽空整理一篇,记录下开发历程......——前言

    需求描述

    可以选择日期,按月份分别查看应出勤数、已出勤数、迟到数、早退数,用特殊标记标出某天是迟到还是早退等等,选中某天,直接加载该天的所有考勤记录,看上去挺简单的功能,要我写js估计可以写到吐血,还好懂得拿来主义,网上找个开源的日历组件,然后进行改造。日历组件源码地址Calendar.js由于公司没有平面和美工,也没有前端,所以这些活我就兼做了,所以大家不要对界面吐槽,我已经尽力了,555~,下面的界面截图我都是用的谷歌浏览器,模拟iphone6的效果,同真机上比自然会有一定的出入,通常来说真机上面要比模拟器上面更漂亮和清晰,界面效果如下:

    注:橙色表示当前日期,浅蓝色表示选中日期,默认情况下显示当前日期,并加载当天的考勤记录。

    功能实现

    之前本来打算使用区域滚动的,后面看见原型界面是整个页面滚动,所以我就暂时注释了这块。

    日历支持左右滑动进行翻页(按月进行翻),顶部按钮也支持翻页。

    技术选型:mui、h5、h5+、vue.js

    html代码如下:

    <!doctype html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>我的考勤</title>
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
        <link href="../../css/mui.min.css" rel="stylesheet" />
        <link rel="stylesheet" href="../../css/base.css" />
        <link rel="stylesheet" href="../../css/app/home/timeline.css" />
        <link rel="stylesheet" href="../../css/app/my/punch-card.css" />
        <link rel="stylesheet" href="../../css/calendar.css" />
    </head>
    <body>
        <header class="mui-bar mui-bar-nav">
            <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
            <h1 class="mui-title">我的考勤</h1><span id="bigTime" class="bigTime" style="visibility:hidden;"></span>
        </header>
        <div id="app" class="mui-content">
            <div class="div-yearmonth">
                <i id="prePage" class="mui-icon iconfont icon-shangyiye"></i>
                <span class="spn-today"><i class="mui-icon iconfont icon-rili"></i><span id="timeNow"></span></span>
                <i id="nextPage" class="mui-icon iconfont icon-xiayiye"></i>
            </div>
            <div class="div-operate">
                <div class="mui-segmented-control ul-operate">
                    <a class="mui-control-item mui-active" v-on:tap="getDataByType(1)">
                        <p><span v-text="obj.attendance"></span></p>
                        <p>应出勤</p>
                    </a>
                    <a class="mui-control-item" v-on:tap="getDataByType(2)">
                        <p><span v-text="obj.actualAttendance"></span></p>
                        <p>实际出勤</p>
                    </a>
                    <a class="mui-control-item" v-on:tap="getDataByType(3)">
                        <p><span v-text="obj.beLate"></span></p>
                        <p>迟到</p>
                    </a>
                    <a class="mui-control-item" v-on:tap="getDataByType(4)">
                        <p><span v-text="obj.leaveEarly"></span></p>
                        <p>早退</p>
                    </a>
                </div>
            </div>
            <div id="container"></div>
            <div class="div-list">
                <div class="line"></div>
                <div class="date"><span class="spn-date"><i v-text="monthDay" class="monthDay"></i><i v-text="week">星期一</i></span></div>
                <!--<div id="mui-scroll-wrapper" class="mui-scroll-wrapper timeline">
                    <div class="mui-scroll">-->
                        <!--这里放置真实显示的DOM内容-->
                        <section v-if="list.length>0" id="cd-timeline" class="cd-container">
                            <div v-for="(item,index) in list" class="cd-timeline-block">
                                <div class="cd-timeline-img cd-picture" v-bind:class="{first:!index}"><span class="worktag">早班上班</span></div>
                                <div class="cd-timeline-content">
                                    <div class="timeline-head">
                                        <span class="fl" v-text="item.name"></span>
                                        <span class="fl">打卡时间</span><span class="fl" v-text="item.time"></span>
                                        <span v-if="item.errorType!=''" class="mui-badge fl" v-bind:class="g.getTimeCardTypeBcByVal(item.errorType)" v-text="g.getTimeCardTypeByVal(item.errorType)"></span>
                                    </div>
                                    <div class="div-address"><i class="mui-icon mui-icon-location"></i><span v-text="item.address"></span></div>
                                </div>
                            </div>
                        </section>
                        <div v-else>
                            <div class="emptyinfo">
                                <span class="mui-icon mui-icon-location"></span>
                                <p>您今天未打卡哦~</p>
                            </div>
                        </div>
                    <!--</div>
                </div>-->
            </div>
        </div>
        <script src="../../js/mui.min.js"></script>
        <script type="text/javascript" src="../../js/libs/vue.min.js"></script>
        <script type="text/javascript" src="../../js/common/config.js"></script>
        <script type="text/javascript" src="../../js/common/global.js"></script>
        <script type="text/javascript" src="../../js/libs/calendar.js"></script>
        <script type="text/javascript">
            var canlendar = null;
            mui.init();
            mui.ready(function () {
                //g.initScroll({ h: '300px' });//区域滚动
            });
            var app = new Vue({
                el: "#app",
                data: {
                    obj: {
                        attendance: '',
                        actualAttendance: '',
                        beLate: '',
                        leaveEarly: ''
                    },
                    appData: {
                        attendance: [],
                        actualAttendance: [],
                        beLate: [],
                        leaveEarly: []
                    }, //不同考勤类型数据
                    monthDay: g.getDatePart('month') + '/' + g.getDatePart('day'), //月/日
                    week: g.getDatePart('week'), //星期几
                    list: []
                },
                mounted: function () {
                    var _self = this;
                    eventListener();
                    initHandleData(_self); //1
                    canlendar = new Calendar({
                        parentNode: document.getElementById("container"),
                        appData: _self.appData,
                        sltDateFuc:_self.sltDateFuc
                    }); //2注意顺序
                    mui.plusReady(function () {
                        var wv = plus.webview.currentWebview();
                        _self.userName = wv.userName;
                        _self.roleName = wv.roleName;
                        _self.imgUrl = wv.imgUrl;
                    })
                },
                methods: {
                    //回调函数,根据日期获取考勤记录
                    sltDateFuc: function (date) {
                        //test
                        console.log(date);
                        var sltDate = g.convertDateFromString(date);
                        this.monthDay = g.getDatePart('month', sltDate) + '/' + g.getDatePart('day', sltDate); //月/日
                        this.week = g.getDatePart('week', sltDate); //星期几
                        if (date == '2017-11-11') {
                            this.list = [{
                                name: '早班上班',
                                address: '广东省深圳市南山区学苑大道1001号南山智园C3栋5楼',
                                time: '08:20',
                                tag: 1,
                                errorType: '1'
                            },
                        {
                            name: '早班上班',
                            address: '广东省深圳市南山区学苑大道1001号南山智园C3栋5楼',
                            time: '09:20',
                            tag: 1,
                            errorType: '2'
                        },
                        {
                            name: '中班上班',
                            address: '广东省深圳市南山区学苑大道1001号南山智园C3栋5楼',
                            time: '12:20',
                            tag: 1,
                            errorType: ''
                        }
                            ];
                        } else if (date == '2017-11-10') {
                            this.list = [{
                                name: '晚班上班',
                                address: '广东省深圳市南山区学苑大道1001号南山智园C3栋5楼',
                                time: '21:20',
                                tag: 1,
                                errorType: '1'
                            },
                        {
                            name: '晚班上班',
                            address: '广东省深圳市南山区学苑大道1001号南山智园C3栋5楼',
                            time: '22:20',
                            tag: 1,
                            errorType: '2'
                        },
                        {
                            name: '晚班上班',
                            address: '广东省深圳市南山区学苑大道1001号南山智园C3栋5楼',
                            time: '23:20',
                            tag: 1,
                            errorType: ''
                        }
                            ];
                        } else {
                            this.list = [];
                        }
                    },
                    //切换考勤类型
                    getDataByType: function (t) {
                        var result = [];
                        switch (t) {
                            case 1: //应出勤
                                app.appData.attendance = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27];
                                app.appData.beLate = [];
                                app.appData.leaveEarly = [];
                                app.appData.actualAttendance = [];
                                break;
                            case 2: //实际出勤
                                app.appData.actualAttendance = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27];
                                app.appData.attendance = [];
                                app.appData.leaveEarly = [];
                                app.appData.beLate = [];
                                break;
                            case 3: //迟到
                                app.appData.beLate = [3, 5];
                                app.appData.actualAttendance = [];
                                app.appData.attendance = [];
                                app.appData.leaveEarly = [];
                                break;
                            default: //早退
                                app.appData.leaveEarly = [11, 7, 21];
                                app.appData.attendance = [];
                                app.appData.actualAttendance = [];
                                app.appData.beLate = [];
                                break;
                        }
                        app.list = result;
                        canlendar = new Calendar({
                            parentNode: document.getElementById("container"),
                            appData: app.appData,
                            sltDateFuc: app.sltDateFuc
                        });
                    }
                }
            });
    
            function eventListener() {
                //上月
                document.getElementById('prePage').addEventListener('tap', function () {
                    console.log('prePage')
                    canlendar.turnPre();
                    var str = canlendar.getPreMonth(g.id("bigTime").innerHTML);
                    updateMonth(str);
                })
                //下月
                document.getElementById('nextPage').addEventListener('tap', function () {
                    canlendar.turnNext();
                    var str = canlendar.getNextMonth(g.id("bigTime").innerHTML);
                    updateMonth(str);
                })
            }
    
            function updateMonth(str) {
                var year = str.substring(0, 4);
                var month = str.substr(5, 2);
                var r = year + '' + month + '';
                g.id("bigTime").innerHTML = str;
                g.id("timeNow").innerHTML = r;
            }
    
            function initHandleData(app) {
                app.obj.attendance = 27;
                app.obj.actualAttendance = 26;
                app.obj.beLate = 2;
                app.obj.leaveEarly = 3;
            }
        </script>
    </body>
    </html>
    View Code

    数据我都是模拟的假数据,所以看见显示有问题不要奇怪,实际项目自然是用ajax调用api接口进行数据填充。咋一看就知道这里面用到了日期和垂直时间线。

    calendar.js我是在别人的calendar组件基础之上进行修改的,代码如下:

    /**
     * Created by zouqj on 17/11/10
     */
    var doc = window.document;
    var Calendar = function (options) {
        "use strict";
        //默认参数
        var defaults = {
            //中文格式内容
            appData: { attendance: [], actualAttendance: [], beLate: [], leaveEarly: [] },//界面传过来的数据
            sltDateFuc: function (sltDate) { },//选中日期回调函数
            monthNames: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
            dayNames: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
            dayLongNames: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
            holiday: {
                "1-1": "元旦",
                "2-2": "湿地日",
                "2-14": "情人节",
                "3-8": "妇女节",
                "3-12": "植树节",
                "3-15": "消费者权益日",
                "4-1": "愚人节",
                "4-22": "地球日",
                "5-1": "劳动节",
                "5-4": "青年节",
                "5-12": "护士节",
                "5-18": "博物馆日",
                "6-1": "儿童节",
                "6-5": "环境日",
                "6-23": "奥林匹克日",
                "6-24": "骨质疏松日",
                "7-1": "建党节",
                "8-1": "建军节",
                "9-3": "抗战胜利日",
                "9-10": "教师节",
                "10-1": "国庆节",
                "11-17": "学生日",
                "12-1": "艾滋病日",
                "12-24": "平安夜",
                "12-25": "圣诞节"
            },
    
            firstDay: 1,                // 从周一开始,计算
            weekendDays: [0, 6],        // 休息日为:周六, 周日
            dateFormat: 'yyyy-mm-dd',   // 打印格式, formatDate 对应
            limitDis: 80,              // 拖拽限制距离,当大于该距离时,触发页面切换
            weekHandler: "dayThead",   // 星期title内容所在类
            monthContainer: "dateUl",  // 日期内容所在容器类
            toolBar: "timeChoose",     // 工具条所在类
            parentNode: document.body, // 组件插入容器,默认body
            template: // '<div class="pannel" id="timePannel"></div>'                 
                       //+    '<div class="aside">'
                       //+        '<header class="timeNow"></header>'
                       //+        '<div class="dateContain">'
                       //+            '<div class="bigTime"></div>'
                       //+            '<div class="noliDate"></div>'
                       //+            '<div class="goodBad">'
                       //+                '<div class="gooList"></div>'
                       //+                '<div class="badList"></div>'       
                       //+            '</div>'
                       //+        '</div>'
                       //+    '</div>'
                        '<div class="container">'
                       + '<div class="main">'
                       + '<div class="operator">'
                       + '<div class="goPrev">'
                       + '<i class="icon icon-left"></i>'
                       + '</div>'
                       + '<div class="goNext">'
                       + '<i class="icon icon-right"></i>'
                       + '</div>'
                       + '<div class="timeChoose"></div>'
                       + '</div>'
                       + '<div class="datePicker">'
                       + '<div class="dayThead"></div>'
                       + '<div class="dateUlContainer">'
                       + '<div class="dateUl">'
                       + '<div class="dateLi">'
                       //+ '<div class="dayTbody"></div>'
                       + '</div>'
                       + '</div>'
                       + '</div>'
                       + '</div>'
                       + '</div>'
                       + '</div>'
        };
        //参数调整
        options = options || {};
        for (var prop in defaults) {
            if (typeof options[prop] === 'undefined') {
                options[prop] = defaults[prop];
            }
        }
        this.attrs = options;
        //触摸起始点记录
        this.touchesStart = {};
        //初始化内容
        this.init();
    };
    Calendar.prototype = {
        constructor: Calendar,
        init: function (id) {
            //初始化界面
            this.render(id);
            //初始化事件
            this.initEvents();
            //初始布局页面
            this.layout();
            /**
             * 初始化参数
             * this.index     切换页面索引
             * this._initEd   是否初始化完成
             * this._interval 动画切换锁,防止动画重复触发
             * this.offsetValue 切换容器宽度,页面resize时,需要更新该值
             */
            this.index = 0;
            this._initEd = true;
            this._interval = true;
            this.offsetValue = this.monthEle.offsetWidth;
            //节点操作
            this.timeNowEle = doc.querySelector("#timeNow");
            this.bigTimeEle = doc.querySelector(".bigTime");
            //this.noliDateEle = doc.querySelector(".noliDate");
            //this.gooList = doc.querySelector(".gooList");
            this.badList = doc.querySelector(".badList");
            //this.timePannel = doc.getElementById("timePannel");
            this.prevMonthEle = doc.querySelector(".prev-month-html");
            this.currMonthEle = doc.querySelector(".current-month-html");
            this.nextMonthEle = doc.querySelector(".next-month-html");
    
            //初始化 aside页面
            this.setAside();
            //默认加载当天的考勤记录
            var strDate = g.formatDate(new Date(), 'YMD');
            this.attrs.sltDateFuc(strDate);
        },
        render: function () {
            this.attrs.parentNode.innerHTML = this.attrs.template;
        },
        pad2 : function (n) {
            return n < 10 ? '0' + n : n
        },
        /**
         * 设置aside侧边栏内容
         * @param date 指定日期
         */
        setAside: function (date) {
            date = date || new Date();
            var year = date.getFullYear(),
                month = date.getMonth(),
                day = date.getDate();
            var noli = Util.getLunarCalendar(year, month + 1, day);
            var suitTaboo = Util.getSuitAndTaboo(year, month + 1, day);
            //var gooStr = "<i>宜</i>";
            //var badStr = "<i>忌</i>";
            this.timeNowEle.innerHTML = year + "年" + this.pad2(month + 1) + "月";
            //+ "<span>" + this.attrs.dayLongNames[date.getDay()] + "</span>";
            this.bigTimeEle.innerHTML = year + '-' + (month + 1) + '-' + day;
            //this.noliDateEle.innerHTML =   "<p>" + noli["month"] + noli["date"] +"</p>"
            //                             + "<p>" + Util.getSexagenaryCycle(year) + "【" +Util.getZodiac(year) + "】" +"</p>";
    
            //for(var i = 0, len = suitTaboo["suit"].length; i < len; i++) {
            //    gooStr += "<span>" +  suitTaboo["suit"][i] +"</span>";
            //}
            //for(var i = 0, len = suitTaboo["taboo"].length; i < len; i++) {
            //    badStr += "<span>" + suitTaboo["taboo"][i] + "</span>";
            //}
    
            //this.gooList.innerHTML = gooStr;
            //this.badList.innerHTML = badStr;
        },
        /**
         * 初始化事件
         */
        initEvents: function () {
            var self = this;
            var monthEle = this.monthEle = doc.querySelector("." + this.attrs.monthContainer);
            this.timeChooseEle = doc.querySelector(".timeChoose");
    
            this.goPrev = doc.querySelector(".goPrev");
            this.goNext = doc.querySelector(".goNext");
    
            monthEle.addEventListener("mousedown", this._handleTouchStart.bind(this), false);
            monthEle.addEventListener("mousemove", this._handleTouchMove.bind(this), false);
            monthEle.addEventListener("mouseup", this._handleTouchEnd.bind(this), false);
    
            monthEle.addEventListener("touchstart", this._handleTouchStart.bind(this), false);
            monthEle.addEventListener("touchmove", this._handleTouchMove.bind(this), false);
            monthEle.addEventListener("touchend", this._handleTouchEnd.bind(this), false);
    
            monthEle.addEventListener("tap", this._handleClick.bind(this), false);//click change to tap
            monthEle.addEventListener("touchstart", this._handleClick.bind(this), false);
    
            this.goPrev.addEventListener("tap", function (event) {
                self.turnPre();
            }, false);
            this.goNext.addEventListener("tap", function (event) {
                self.turnNext();
            }, false);
            /**
             * BUG: 问题, bind(this)的事件函数, 无法removeEventListener
             * 监听动画完成事件
             */
            monthEle.addEventListener("transitionend", this._transformEnd.bind(this), false);
            monthEle.addEventListener("webkitTransitionEnd", this._transformEnd.bind(this), false);
    
            //操作表操作,事件委托处理
            this.timeChooseEle.addEventListener("tap", this._handleTimeChoose.bind(this), false);
            document.addEventListener("tap", this._handleDocument.bind(this), false);
            //页面resize监听,函数节流,调整布局
            window.addEventListener("resize", this._handleResize.bind(this), false);
        },
        /**
         * 关闭下拉菜单
         * @param event
         * @private
         */
        _handleDocument: function (event) {
            var target = event.target,
                cls = target.className;
            if (cls !== "pullDown") {
                var btns = document.querySelectorAll(".buttonGroup");
                for (var i = 0, len = btns.length; i < len; i++) {
                    btns[i].classList.remove("open");
                }
            }
        },
        /**
         * 工具栏事件绑定, 提供日期变更(年+月 ), 返回今天等功能
         * @param event
         * @private
         */
        _handleTimeChoose: function (event) {
            event.preventDefault();
            var target = event.target,
                parentNode = target.parentNode,
                cls = target.className;
            //排除非元素节点
            if (target.nodeType !== 1) {
                return;
            }
            if (cls === "pullDown") {
                var pCls = parentNode.className.split(" ");
                if (pCls.indexOf("open") === -1) {
                    parentNode.classList.add("open");
                } else {
                    parentNode.classList.remove("open");
                }
            }
            //返回今天
            if (cls === "returnToday" || parentNode.className === "returnToday") {
                this.resetDate(new Date());
            }
            //年份更新
            if (cls === "list-year") {
                var year = parseInt(target.getAttribute("data-year")),
                    month = parseInt(doc.getElementById("op-month-time").textContent) - 1;
                doc.getElementById("op-year-time").textContent = year + "年";
                this.resetDate(new Date(year, month));
            }
            //月份更新
            if (cls === "list-month") {
                var year = parseInt(doc.getElementById("op-year-time").textContent),
                    month = parseInt(target.getAttribute("data-month"));
                doc.getElementById("op-month-time").textContent = month + "月";
                this.resetDate(new Date(year, month));
            }
        },
        _handleResize: function (event) {
            var self = this;
            //函数节流, 重新调整宽度
            self.resizeInterval = setTimeout(function () {
                self.offsetValue = self.monthEle.offsetWidth;
            }, 300)
        },
        _handleClick: function (event) {
            event.preventDefault();
            var target = event.target,
                eleName = target.nodeName;
            if (eleName === "SPAN" || target.className === "dayTd") {
                var aim = eleName === "SPAN" ? target.parentNode : target;
                var year = parseInt(aim.getAttribute("data-year")),
                    month = parseInt(aim.getAttribute("data-month")),
                    day = parseInt(aim.getAttribute("data-day"));
                if (this._oldEle) {
                    this._oldEle.classList.remove("date-selected");
                }
                aim.classList.add("date-selected");
                this._oldEle = aim;
                this.setAside(new Date(year, month, day))
                if (event.type == 'tap') {
                    //根据日期加载打卡记录列表
                    var sltDate = year + '-' + this.pad2(month + 1) + '-' + day;
                    this.attrs.sltDateFuc(sltDate); //执行回调
                }
            }
        },
        _handleTouchStart: function (event) {
            event.preventDefault();
            //屏蔽多次触发
            if (!this._interval) {
                return;
            }
            this.isTouched = true;
            if (event.type === "touchstart") {
                this.touchesStart.x = event.targetTouches[0].pageX;
            } else {
                this.touchesStart.x = event.pageX;
            }
        },
        _handleTouchMove: function (event) {
            event.preventDefault();
            if (!this.isTouched) {
                return;
            }
            this.isMoved = true;
            if (event.type === "touchmove") {
                var pageX = event.targetTouches[0].pageX;
            } else {
                var pageX = event.pageX;
            }
            //横向移动距离
            this.touchesDiff = pageX - this.touchesStart.x;
            this.endPos = pageX;
            //设置样式
            this.monthEle.style[Util.prefix + "transition"] = "all 0ms";
            this.monthEle.style[Util.prefix + "transform"] = "translate3d(" + (this.index * this.offsetValue + this.touchesDiff) + "px, 0px, 0px)";
    
        },
        _handleTouchEnd: function (event) {
            event.preventDefault();
            if (!this.isTouched || !this.isMoved) {
                this.isTouched = false;
                this.isMoved = false;
                return;
            }
            var comPos = this.endPos - this.touchesStart.x;
            //移动距离对比
            if (Math.abs(comPos) < this.attrs.limitDis) {
                this._transformPage();
            } else {
                if (comPos < 0) {
                    this.turnNext();  //下一页
                } else {
                    this.turnPre();   //上一页
                }
            }
            this.isTouched = false;
            this.isMoved = false;
        },
        turnPre: function () {
            if (!this._interval) {
                return;
            }
            this.index++;
            this._isTurnPage = true;
            this._offset = "prev";
            //锁上操作, 防止多次触发
            this._interval = false;
            this._transformPage();
        },
        turnNext: function () {
            if (!this._interval) {
                return;
            }
            this.index--;
            this._isTurnPage = true;
            this._offset = "next";
            //锁上操作, 防止多次触发
            this._interval = false;
            this._transformPage();
        },
        _transformPage: function () {
            this.monthEle.style[Util.prefix + "transition"] = "300ms";
            this.monthEle.style[Util.prefix + "transform"] = "translate3d(" + (this.index * 100) + "%, 0, 0)";
        },
        /**
         * 提示日期tip,仅在移动端有效(宽度 < 425px 触发)
         * @private
         */
        _tipPannel: function () {
            var self = this;
            if (this.offsetValue > 425) {
                return;
            }
            var year = this.value.getFullYear(),
                month = this.value.getMonth() + 1;
            this.timePannel.textContent = year + "年" + month + "月";
            clearTimeout(this.tipInterval);
            this.timePannel.style["display"] = "block";
            //强制relayout,否则动画无效果
            self.timePannel.offsetWidth;
            this.timePannel.style["opacity"] = 1;
            this.tipInterval = setTimeout(function () {
                self.timePannel.style["opacity"] = 0;
                self.timePannel.style["display"] = "none";
            }, 800);
        },
        /**
         * 翻页结束后触发回调事件
         * @private
         */
        _transformEnd: function () {
            //不是翻页不行
            var offset = this._offset;
            if (!this._isTurnPage) {
                return;
            }
            var date = new Date(this.value);
            var year = date.getFullYear(),
                month = date.getMonth();
    
            //下个月
            if (offset === 'next') {
                if (month === 11) {
                    date = new Date(year + 1, 0);
                } else {
                    date = new Date(year, month + 1, 1);
                }
            }
            //上个月
            if (offset === 'prev') {
                if (month === 0) {
                    date = new Date(year - 1, 11);
                } else {
                    date = new Date(year, month - 1, 1);
                }
            }
            this.value = date;
            //this._tipPannel();
    
            this.layout();
            // 重定位
            var index = this.index * -1;
    
            //重新获取 时间容器节点
            this.prevMonthEle = doc.querySelector(".prev-month-html");
            this.currMonthEle = doc.querySelector(".current-month-html");
            this.nextMonthEle = doc.querySelector(".next-month-html");
    
            this.prevMonthEle.style[Util.prefix + "transform"] = "translate3d(" + (index - 1) * 100 + "%, 0px, 0px)";
            this.currMonthEle.style[Util.prefix + "transform"] = "translate3d(" + (index) * 100 + "%, 0px, 0px)";
            this.nextMonthEle.style[Util.prefix + "transform"] = "translate3d(" + (index + 1) * 100 + "%, 0px, 0px)";
    
            doc.getElementById("op-year-time").textContent = this.value.getFullYear() + "年";
            doc.getElementById("op-month-time").textContent = (this.value.getMonth() + 1) + "月";
    
            //恢复锁,可以继续触发
            this._interval = true;
            this._isTurnPage = false;
        },
        /**
         * 指定时间,重置日期内容
         * @param date 时间
         */
        resetDate: function (date) {
            this.value = date;
            this.index = 0;
            this.monthEle.style[Util.prefix + "transition"] = "all 0ms";
            this.monthEle.style[Util.prefix + "transform"] = "translate3d(0 ,0 ,0)";
            this.prevMonthEle.style[Util.prefix + "transform"] = "translate3d(-100%, 0px, 0px)";
            this.currMonthEle.style[Util.prefix + "transform"] = "translate3d(0%, 0px, 0px)";
            this.nextMonthEle.style[Util.prefix + "transform"] = "translate3d(100%, 0px, 0px)";
    
            doc.getElementById("op-year-time").textContent = this.value.getFullYear() + "年";
            doc.getElementById("op-month-time").textContent = (this.value.getMonth() + 1) + "月";
    
            this.layout();
        },
        /**
         * 布局函数
         */
        layout: function () {
            var layoutDate = this.value ? this.value : new Date().setHours(0, 0, 0, 0);
            this.value = layoutDate;
    
            //三个月的 HTML信息
            var prevMonthHTML = this.monthHTML(layoutDate, 'prev');
            var currentMonthHTML = this.monthHTML(layoutDate);
            var nextMonthHTML = this.monthHTML(layoutDate, 'next');
            var monthHTML = '<div class="dateLi prev-month-html"><div class="dayTbody">' + prevMonthHTML + "</div></div>"
                            + '<div class="dateLi current-month-html"><div class="dayTbody">' + currentMonthHTML + "</div></div>"
                            + '<div class="dateLi next-month-html"><div class="dayTbody">' + nextMonthHTML + "</div></div>"
    
            if (!this._initEd) {
                //初次渲染的时候使用, 否则不使用
                //渲染 星期头部
                var weekHeaderHTML = [];
                for (var i = 0; i < 7; i++) {
                    var weekDayIndex = (i + this.attrs.firstDay > 6) ? (i - 7 + this.attrs.firstDay) : (i + this.attrs.firstDay);
                    var dayName = this.attrs.dayNames[weekDayIndex];
                    if (this.attrs.weekendDays.indexOf(weekDayIndex) !== -1) {
                        //休息日样式
                        weekHeaderHTML.push('<div class="dayTd active">' + dayName + '</div>');
                    } else {
                        weekHeaderHTML.push('<div class="dayTd">' + dayName + '</div>');
                    }
                }
    
                var yearSelectHTML = [],
                    monthSelectHTML = [];
                for (var i = 1900; i <= 2050; i++) {
                    var str = "<li class='list-year' data-year='" + i + "'>" + i + "年</li>";
                    yearSelectHTML.push(str);
                }
                for (var i = 1; i <= 12; i++) {
                    var str = "<li class='list-month' data-month='" + (i - 1) + "'>" + i + "月</li>";
                    monthSelectHTML.push(str);
                }
    
                doc.querySelector("." + this.attrs.weekHandler).innerHTML = weekHeaderHTML.join("");
                doc.querySelector("." + this.attrs.toolBar).innerHTML = '<div class="yearChoose">'
                                                                        + '<div class="chooseContainer">'
                                                                        + '<div class="buttonGroup">'
                                                                        + '<span class="yearTime" id="op-year-time">' + new Date().getFullYear() + '年</span>'
                                                                        + '<span class="pullDown">+</span>'
                                                                        + '</div>'
                                                                        + '<div class="pullSelect">'
                                                                        + '<ul>' + yearSelectHTML.join('') + '</ul>'
                                                                        + '</div>'
                                                                        + '</div>'
                                                                        + '</div>'
                                                                        + '<div class="monthChoose">'
                                                                        + '<div class="chooseContainer">'
                                                                        + '<div class="buttonGroup">'
                                                                        + '<span class="monthTime" id="op-month-time">' + (new Date().getMonth() + 1) + '月</span>'
                                                                        + '<span class="pullDown">+</span>'
                                                                        + '</div>'
                                                                        + '<div class="pullSelect">'
                                                                        + '<ul>' + monthSelectHTML.join('') + '</ul>'
                                                                        + '</div>'
                                                                        + '</div>'
                                                                        + '</div>'
                                                                        + '<div class="returnToday"><span>返回今天</span></div>'
            }
            doc.querySelector("." + this.attrs.monthContainer).innerHTML = monthHTML;
        },
        /**
         * 获取当月总天数
         * @param date 日期
         */
        totalDaysInMonth: function (date) {
            var d = new Date(date);
            return new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate();
        },
        /**
         * 日期HTML设置
         * @param date   设置时间
         * @param offset 设置偏移 ["next" -> "下个月"  "prev" -> "上个月"]
         * @returns {string} 返回拼接好的HTML字符串
         */
        monthHTML: function (date, offset) {
            var date = new Date(date);
            var year = date.getFullYear(),
                month = date.getMonth(),
                day = date.getDate();
    
            //下个月
            if (offset === 'next') {
                if (month === 11) {
                    date = new Date(year + 1, 0);
                } else {
                    date = new Date(year, month + 1, 1);
                }
            }
            //上个月
            if (offset === 'prev') {
                if (month === 0) {
                    date = new Date(year - 1, 11);
                } else {
                    date = new Date(year, month - 1, 1);
                }
            }
            //调整时间
            if (offset === 'next' || offset === 'prev') {
                month = date.getMonth();
                year = date.getFullYear();
            }
    
            //上月 | 本月 总天数, 本月第一天索引
            var daysInPrevMonth = this.totalDaysInMonth(new Date(date.getFullYear(), date.getMonth()).getTime() - 10 * 24 * 60 * 60 * 1000),
                daysInMonth = this.totalDaysInMonth(date),
                firstDayOfMonthIndex = new Date(date.getFullYear(), date.getMonth()).getDay();
    
            if (firstDayOfMonthIndex === 0) {
                firstDayOfMonthIndex = 7;
            }
    
            var dayDate,
                rows = 5,//日历行数
                cols = 7,
                monthHTML = [],
                dayIndex = 0 + (this.attrs.firstDay - 1),
                today = new Date().setHours(0, 0, 0, 0);
    
            for (var i = 1; i <= rows; i++) {
                var row = i;
                var tdList = [];
                for (var j = 1; j <= cols; j++) {
                    var col = j;
                    dayIndex++;
    
                    var dayNumber = dayIndex - firstDayOfMonthIndex;
                    //要添加的类名, 默认dayTd
                    var classNames = ["dayTd"];
                    if (dayNumber < 0) {
                        //上个月日期
                        classNames.push("date-prev");
                        dayNumber = daysInPrevMonth + dayNumber + 1;
                        dayDate = new Date(month - 1 < 0 ? year - 1 : year, month - 1 < 0 ? 11 : month - 1, dayNumber).getTime();
                    } else {
                        dayNumber = dayNumber + 1;
                        if (dayNumber > daysInMonth) {
                            //下个月日期
                            classNames.push("date-next");
                            dayNumber = dayNumber - daysInMonth;
                            dayDate = new Date(month + 1 > 11 ? year + 1 : year, month + 1 > 11 ? 0 : month + 1, dayNumber).getTime();
                        } else {
                            dayDate = new Date(year, month, dayNumber).getTime();
                        }
                    }
                    //今天 date-current
                    if (dayDate === today) {
                        classNames.push("date-current");
                    }
                    //周六日 date-reset
                    if (dayIndex % 7 === this.attrs.weekendDays[0] || dayIndex % 7 === this.attrs.weekendDays[1]) {
                        classNames.push("date-reset");
                    }
                    dayDate = new Date(dayDate);
    
                    var dayYear = dayDate.getFullYear();
                    var dayMonth = dayDate.getMonth();
    
                    //农历日期
                    var ccalendar = Util.getLunarCalendar(dayYear, dayMonth + 1, dayNumber);
                    var holiday = this.attrs.holiday[(dayMonth + 1) + "-" + dayNumber];
                    //节日显示,优先级别:公历节日 > 农历节日 > 节气 > 农历 date-holiday
                    if (holiday) {
                        var alamanac = holiday;
                        classNames.push("date-holiday");
                    } else {
                        if (ccalendar["festival"]) {
                            var alamanac = ccalendar["festival"];
                            classNames.push("date-holiday");
                        } else {
                            if (ccalendar["solarTerm"]) {
                                var alamanac = ccalendar["solarTerm"];
                                classNames.push("date-holiday");
                            } else {
                                var alamanac = ccalendar["date"];
                            }
                        }
                    }
                    //集合包含dayNumber
                    var _appData = this.attrs.appData;
                    var _tagHtml = '';
                    if (_appData.attendance.contains(dayNumber))//应出勤
                    {
                        classNames.push("attendance");
                    }
                    if (_appData.actualAttendance.contains(dayNumber)) {//实际出勤
                        classNames.push("actualAttendance");
                    }
                    if (_appData.beLate.contains(dayNumber)) {//迟到
                        classNames.push("beLate");
                        _tagHtml = '<i class="fl font-danger">迟</i>';
                    }
                    if (_appData.leaveEarly.contains(dayNumber)) {//早退
                        _tagHtml = '<i class="fl font-warning">退</i>';
                        classNames.push("leaveEarly");
                    }
                    tdList.push(
                          '<div class="' + classNames.join(" ") + '" data-year=' + dayYear + ' data-month=' + dayMonth + ' data-day=' + dayNumber + '>'      
                        + '<span class="dayNumber">' + _tagHtml  +dayNumber + "</span>"
                        + '<span class="almanac">' + alamanac + "</span>"
                        + '</div>'
                    )
                }
                monthHTML.push(
                    '<div class="dayTr">' + tdList.join("") + '</div>'
                )
            }
            return monthHTML.join("");
        },
        /**
         * 格式化日期内容
         * @param date
         * @returns {string|XML}
         */
        formatDate: function (date) {
            date = new Date(date);
            var year = date.getFullYear();
            var month = date.getMonth();
            var month1 = month + 1;
            var day = date.getDate();
            var weekDay = date.getDay();
            return this.attrs.dateFormat
                .replace(/yyyy/g, year)
                .replace(/yy/g, (year + '').substring(2))
                .replace(/mm/g, month1 < 10 ? '0' + month1 : month1)
                .replace(/m/g, month1)
                .replace(/MM/g, this.attrs.monthNames[month])
                .replace(/dd/g, day < 10 ? '0' + day : day)
                .replace(/d/g, day)
                .replace(/DD/g, this.attrs.dayNames[weekDay])
        },
        /**
        * 获取上一个月
        * @date 格式为yyyy-mm-dd的日期,如:2014-01-25
        */
        getPreMonth: function (date) {
            var arr = date.split('-');
            var year = arr[0]; //获取当前日期的年份
            var month = arr[1]; //获取当前日期的月份
            var day = arr[2]; //获取当前日期的日
            var days = new Date(year, month, 0);
            days = days.getDate(); //获取当前日期中月的天数
            var year2 = year;
            var month2 = parseInt(month) - 1;
            if (month2 == 0) {
                year2 = parseInt(year2) - 1;
                month2 = 12;
            }
            var day2 = day;
            var days2 = new Date(year2, month2, 0);
            days2 = days2.getDate();
            if (day2 > days2) {
                day2 = days2;
            }
            if (month2 < 10) {
                month2 = '0' + month2;
            }
            var t2 = year2 + '-' + month2 + '-' + day2;
            return t2;
        },
    
        /**
         * 获取下一个月
         * @date 格式为yyyy-mm-dd的日期,如:2014-01-25
         */
        getNextMonth: function (date) {
            var arr = date.split('-');
            var year = arr[0]; //获取当前日期的年份
            var month = arr[1]; //获取当前日期的月份
            var day = arr[2]; //获取当前日期的日
            var days = new Date(year, month, 0);
            days = days.getDate(); //获取当前日期中的月的天数
            var year2 = year;
            var month2 = parseInt(month) + 1;
            if (month2 == 13) {
                year2 = parseInt(year2) + 1;
                month2 = 1;
            }
            var day2 = day;
            var days2 = new Date(year2, month2, 0);
            days2 = days2.getDate();
            if (day2 > days2) {
                day2 = days2;
            }
            if (month2 < 10) {
                month2 = '0' + month2;
            }
            var t2 = year2 + '-' + month2 + '-' + day2;
            return t2;
        }
    };
    var Util = {
        /**
         * css前缀判断,仅执行一次
         */
        prefix: (function () {
            var div = document.createElement('div');
            var cssText = '-webkit-transition:all .1s; -moz-transition:all .1s; -o-transition:all .1s; -ms-transition:all .1s; transition:all .1s;';
            div.style.cssText = cssText;
            var style = div.style;
            if (style.transition) {
                return '';
            }
            if (style.webkitTransition) {
                return '-webkit-';
            }
            if (style.MozTransition) {
                return '-moz-';
            }
            if (style.oTransition) {
                return '-o-';
            }
            if (style.msTransition) {
                return '-ms-';
            }
        })(),
        /**
         * 公历转化为积日(积日:1900年1月0日到当天的天数
         * @param year  年份
         * @param month 月份
         * @param day   日期
         * @returns {number}
         * @private
         */
        _gregorianCalendarToAccumulateDate: function (year, month, day) {
            var accumulateDate = 0;
            accumulateDate += (year - 1900) * 365;  //假设每年365天,计算天数
            accumulateDate += parseInt((year - 1901) / 4);  //将闰年数累加计数
            for (var eachMonth = month - 1; eachMonth > 0; eachMonth--) {
                accumulateDate += (new Date(year, eachMonth, 0)).getDate();  //累加当年各月天数
            }
            accumulateDate += day;  //累加最后一月天数
            return accumulateDate;  //返回公历日期对应积日
        },
        /**
         * 计算积日的农历日期
         * @param accumulateDate
         * @returns {number}
         * @private
         */
        _getLunarDate: function (accumulateDate) {
            //逆推估算是第几个朔日
            var reverseCalends = parseInt((accumulateDate - 1.6) / 29.5306);
            var calends = reverseCalends - 1;
            do {
                calends++;
                //计算朔日积日
                var calendsAccumulateDate = parseInt(1.6 + 29.5306 * calends + 0.4 * Math.sin(1 - 0.45058 * calends));
                var solarTermDate = accumulateDate - calendsAccumulateDate + 1;
            } while (solarTermDate >= 30);
            //下一个朔日在当天的次日,当月即为大月,当日为农历三十
            if (solarTermDate === 0)
                return 30;
            else
                return solarTermDate;
        },
        /**
         * 计算某年某个节气的积日(公式)
         * @param differenceYear
         * @param solarTermSerialNumber
         * @returns {Number}
         * @private
         */
        _getSolarTermAccumulateDate: function (differenceYear, solarTermSerialNumber) {
            var solarTermAccumulateDate = parseInt(365.242 * differenceYear + 6.2 + 15.22 * solarTermSerialNumber - 1.9 * Math.sin(0.262 * solarTermSerialNumber));
            return solarTermAccumulateDate;
        },
        /**
         * 获取农历日期
         * @param year
         * @param month
         * @param day
         * @returns {{month: string, date: string, solarTerm: string, festival: *}}
         */
        getLunarCalendar: function (year, month, day) {
            //常量数组
            var monthName = ["正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "腊月"];
            var dateName = ["十", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
            var datePrefixName = ["初", "十", "廿", "三"];
            var solarTermName = ["小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "露水", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪", "冬至"];
            var festivalName = {
                "0101": "春节",
                "0115": "元宵节",
                "0202": "龙头节",
                "0505": "端午",
                "0707": "七夕",
                "0715": "中元节",
                "0815": "中秋",
                "0909": "重阳节",
                "1001": "寒衣节",
                "1015": "下元节",
                "1208": "腊八节",
                "1223": "小年",
                "1230": "除夕"
            };
    
            var differenceYear = year - 1900;  //年份距1900年差值
            var solarTermSerialNumber = month * 2 - 1;  //节气序号
            var lunarCalendarMonth = (month - 1 + 12) % 12;  //理论农历月份
            var accumulateDate = Util._gregorianCalendarToAccumulateDate(year, month, day);  //计算当前日期积日
            var lunarDate = Util._getLunarDate(accumulateDate);  //计算农历日期
    
            //计算前一个月、当月、后一个月、前半个月以及后半个月的节气日期(STLD)和节气积日(STAD)
            var curSTLD = Util._getLunarDate(Util._getSolarTermAccumulateDate(differenceYear, solarTermSerialNumber));
            var prevSTLD = Util._getLunarDate(Util._getSolarTermAccumulateDate(differenceYear, solarTermSerialNumber - 2));
            var nextSTLD = Util._getLunarDate(Util._getSolarTermAccumulateDate(differenceYear, solarTermSerialNumber + 2));
            var halfPrevSTLD = Util._getLunarDate(Util._getSolarTermAccumulateDate(differenceYear, solarTermSerialNumber - 1));
            var halfNextSTLD = Util._getLunarDate(Util._getSolarTermAccumulateDate(differenceYear, solarTermSerialNumber + 1));
            var curSTAD = Util._getSolarTermAccumulateDate(differenceYear, solarTermSerialNumber);
            var prevSTAD = Util._getSolarTermAccumulateDate(differenceYear, solarTermSerialNumber - 2);
            var nextSTAD = Util._getSolarTermAccumulateDate(differenceYear, solarTermSerialNumber + 2);
            var halfPrevSTAD = Util._getSolarTermAccumulateDate(differenceYear, solarTermSerialNumber - 1);
            var halfNextSTAD = Util._getSolarTermAccumulateDate(differenceYear, solarTermSerialNumber + 1);
    
            //通过节气日期判断闰月情况,调整月份
            if (accumulateDate < curSTAD && lunarDate + curSTAD - accumulateDate !== curSTLD)
                lunarCalendarMonth--;
            else if (accumulateDate > curSTAD && lunarDate - (accumulateDate - curSTAD) !== curSTLD && lunarDate + nextSTLD - accumulateDate === nextSTAD)
                lunarCalendarMonth++;
    
            //判断是否是节气
            if (curSTAD === accumulateDate)
                var solarTerm = solarTermName[solarTermSerialNumber];
            else if (halfPrevSTAD === accumulateDate)
                var solarTerm = solarTermName[solarTermSerialNumber - 1];
            else if (halfNextSTAD === accumulateDate)
                var solarTerm = solarTermName[solarTermSerialNumber + 1];
    
            //计算是否节日
            var monthNumber = lunarCalendarMonth;
            if (monthNumber < 10)
                var festivalNumber = "0" + monthNumber;
            else
                var festivalNumber = monthNumber;
            if (lunarDate < 10)
                festivalNumber += "0" + lunarDate;
            else
                festivalNumber += lunarDate;  //拼接字符串
            var festivalString = festivalName[festivalNumber];  //调用节日
    
            //计算农历名称
            var monthString = monthName[(monthNumber + 11) % 12];  //月份名称
            var prefix = parseInt((lunarDate - 1) / 10);
            if (lunarDate === 20 || lunarDate === 30)
                var dateString = datePrefixName[prefix + 1];
            else
                var dateString = datePrefixName[prefix];
            dateString += dateName[lunarDate % 10];  //日期名称
    
            //返回结果
            var result = {
                'month': monthString,
                'date': dateString,
                'solarTerm': solarTerm,
                'festival': festivalString
            };
            return result;
        },
        /**
         * 判断年份干支
         * @param year 公历年份
         * @returns {string} 返回干支
         */
        getSexagenaryCycle: function (year) {
    
            //常量数组
            var heavenlyStems = ["癸", "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬"];
            var earthlyBranches = ["亥", "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌"];
    
            //计算与1963年的差值(1964年为甲子年)
            var yearSerialNumber = year - 1863;
    
            //拼接该年干支
            var sexagenaryCycle = heavenlyStems[yearSerialNumber % 10];
            sexagenaryCycle += earthlyBranches[yearSerialNumber % 12];
            sexagenaryCycle += "年";
            return sexagenaryCycle;
        },
        /**
         * 获取生肖年份
         * @param year
         * @returns {string}
         */
        getZodiac: function (year) {
            //常量数组
            var zodiacName = ["猪年", "鼠年", "牛年", "虎年", "兔年", "龙年", "蛇年", "马年", "羊年", "猴年", "鸡年", "狗年"];
    
            //计算与1963年的差值(1964年为甲子年)
            var yearSerialNumber = year - 1863;
    
            return zodiacName[yearSerialNumber % 12];
        },
        /**
         * 玄学啊,获取禁忌事情
         * @param year
         * @param month
         * @param day
         * @returns {{suit: string, taboo: string}}
         */
        getSuitAndTaboo: function (year, month, day) {
    
            var suit = ["开光", "嫁娶", "入宅", "上梁", "祭祀", "出行", "作灶", "破土", "订盟", "祈福"];
            var taboo = ["纳采", "冠笄", "竖柱", "掘井", "伐木", "理发", "交易", "探病", "雕刻", "斋醮"];
    
            var dateString = parseInt((year * month * day) % 1025).toString(2);
            var len = dateString.length;
            if (len < 10)
                for (; len < 10 ; len++)
                    dateString = "0" + dateString;
            dateString = dateString.split("").reverse().join("");
            var dateNum = parseInt(dateString, 2);
            var suitResult = [];
            var tabooResult = [];
    
            for (var i = 0; i < 10; i++) {
                if (dateNum % 2)
                    suitResult.push(taboo[i]);
                else
                    tabooResult.push(suit[i]);
                dateNum = parseInt(dateNum / 2);
            }
    
            var suitString = suitResult;
            var tabooString = tabooResult;
            var result = {
                'suit': suitString,
                'taboo': tabooString
            }
            return result;
        }
    };
    View Code

    calendar.css也是一样,我进行了改造,代码如下:

    html {
      font-size: 16px;-ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;/*不用10px 62.5% 因为chrome只支持12px最小*/
    }
    *,*:before,*:after {
      box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    }
    [hidden],template {display: none;}
    a {background-color: transparent;text-decoration: none;}
    a:active,a:hover {outline: 0;}
    abbr[title] {border-bottom: 1px dotted;}
    b,strong {font-weight: bold;}
    dfn {font-style: italic;}
    mark {background: #ff0;color: #000;}
    small{font-size: 80%;}
    sub,sup {font-size: 75%;line-height: 0;position: relative;vertical-align: baseline;}
    sup {top: -0.5em;}
    sub {bottom: -0.25em;}
    img {border: 0;}
    svg:not(:root) {overflow: hidden;}
    figure {margin: 1em 40px;}
    hr {box-sizing: content-box;height: 0;}
    pre {overflow: auto;}
    code,kbd,pre,samp {
      font-family: monospace, monospace;font-size: 1em;
    }
    button,input,optgroup,select,textarea {
      color: inherit;font: inherit;margin: 0;
    }
    a,input,textarea,select,button {
      outline: 0;
    }
    button {overflow: visible;}
    button,select {text-transform: none;}
    button,html input[type="button"],input[type="reset"],input[type="submit"] {
      -webkit-appearance: button;cursor: pointer;
    }
    button[disabled],html input[disabled] {
      cursor: default;
    }
    button::-moz-focus-inner,input::-moz-focus-inner {
      border: 0;padding: 0;
    }
    input {
      line-height: normal;
    }
    input[type="checkbox"],
    input[type="radio"] {
      box-sizing: border-box;padding: 0;
    }
    input[type="number"]::-webkit-inner-spin-button,
    input[type="number"]::-webkit-outer-spin-button {
      height: auto;
    }
    input[type="search"] {
      -webkit-appearance: textfield;box-sizing: content-box;
    }
    input[type="search"]::-webkit-search-cancel-button,
    input[type="search"]::-webkit-search-decoration {
      -webkit-appearance: none;
    }
    fieldset {
      border: 1px solid #c0c0c0;margin: 0 2px;padding: 0.35em 0.625em 0.75em;
    }
    legend {border: 0;padding: 0;}
    textarea {overflow: auto;}
    optgroup {font-weight: bold;}
    .button:active {color: #0a8ddf;border-color: #0a8ddf;}
    /*p {margin: 1em 0;}*/
    body {
      position: absolute;top: 0;right: 0;bottom: 0;left: 0;overflow: hidden;
    }
    @font-face {
      font-family: "icon-yuan";src: url("../fonts/icomoon.ttf");
    }
    .icon {
      font-family: icon-yuan !important;font-style: normal;display: inline-block;vertical-align: -2px;
    }
    .icon-left:after {content: 'f053';}
    .icon-right:after {content: 'f054';}
    html {height: 100%;}
    .container {
      width: 100%;
      display: -webkit-box;display: -webkit-flex;display: -ms-flexbox;display: flex;
      -webkit-flex-wrap: wrap; -ms-flex-wrap: wrap;flex-wrap: wrap;height: 100%;
    }
    .container > div {height: 100%;}
    .container .aside {
      color: #ffffff;width: 35%;padding: 15px 20px;
    }
    .container .main {width: 65%;padding-left: 15px;padding-right: 15px;}
    .timeNow {text-align: center;font-size: 0.85rem;}
    .timeNow span:first-child {margin-right: 10px;}
    .operator {position: relative;}
    .operator .goPrev {
      position: absolute;top: 0px;left: 0px;
    }
    .operator .goNext {position: absolute;top: 0px; right: 0px;}
    .operator i {color: #e02d2d;line-height: 2.2rem;cursor: pointer;}
    .operator i:hover {color: #fb0;}
    .dateContain {position: relative;}
    .dateContain .bigTime {
      text-align: center;font-family: arial;font-size: 10rem;
    }
    .dateContain .bigTime span {
      text-shadow: 2px 2px 1px rgba(0, 0, 0, 0.1);
    }
    .dateContain .noliDate > p {
      font-size: 0.85rem;text-align: center;
    }
    .dateContain .goodBad {
      border-top: 2px solid #94c9ff;padding: 10px 7px;
    }
    .dateContain .goodBad > div i {
      font-style: normal;text-shadow: 2px 2px 1px rgba(0, 0, 0, 0.1);
      text-align: center;color: #fff;font-size: 1.1rem;
    }
    .dateContain .goodBad > div span {
      font-size: 0.7rem;margin-left: 8px;
    }
    .aside {
      background: #D2456A;background: -webkit-gradient(linear, 0 0, 0 100%, from(#D2456A), to(#e42355));
    }
    .operator {
      height: 2.2rem;border-bottom: 2px solid #D2456A;
    }
    .datePicker {
      height: calc(100% - 4.4rem);overflow: hidden;
    }
    .dateUl {height: 100%;position: relative;}
    .dateUl .dateLi {height: 100%;position: absolute; width: 100%;}
    .dayThead,.dayTbody,.dayTr {
      display: -webkit-box;display: -webkit-flex;display: -ms-flexbox;display: flex;
      -webkit-flex-wrap: wrap; -ms-flex-wrap: wrap;flex-wrap: wrap;
    }
    .dayTbody {height: calc(100% - 40px);}
    .dayTbody .dayTr {
      width: 100%;border-top: 1px solid #c8cacc; height: calc(100% / 5);
    }
    .dayTbody .dayTr .dayTd {
      display: -webkit-box; display: -webkit-flex;display: -ms-flexbox;display: flex;
      -webkit-box-orient: vertical;-webkit-box-direction: normal;-webkit-flex-direction: column; -ms-flex-direction: column;
      flex-direction: column;-webkit-box-pack: center; -webkit-justify-content: center;-ms-flex-pack: center;justify-content: center;width: calc(14.28571429%);
    }
    .dayTbody .dayTr .dayTd .almanac {
      width: 100%;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;
    }
    .dayTbody .dayTr .dayTd span.dayNumber {
      font-family: arial;color: #000;font-size: 1.2rem; line-height: 21px;height: 18px;
    }
    .dayTbody .dayTr .dayTd span.almanac {
      color: #616161;font-size: 0.7rem;line-height: 25px; height: 21px;
    }
    .dayTbody .dayTr .dayTd.date-reset span:first-child {
      color: #7FAEF5;
    }
    .dayTbody .dayTr .dayTd.date-holiday span:last-child {
      color: #7FAEF5;
    }
    .dayTbody .dayTr .dayTd.date-prev span:first-child,
    .dayTbody .dayTr .dayTd.date-next span:first-child,
    .dayTbody .dayTr .dayTd.date-prev span:last-child,
    .dayTbody .dayTr .dayTd.date-next span:last-child {
      color: #bfbfbf;
    }
    .dayTbody .dayTr .dayTd.date-selected {
      background-color: #47D5FF;
    }
    .dayTbody .dayTr .dayTd.date-selected span:first-child,
    .dayTbody .dayTr .dayTd.date-selected span:last-child {
      color: #fff;
    }
    .dayTbody .dayTr .dayTd.date-current {
      background-color: #fb0;
    }
    .dayTbody .dayTr .dayTd.date-current span:first-child,
    .dayTbody .dayTr .dayTd.date-current span:last-child {
      color: #ffffff !important;
    }
    .prev-month-html {
      -webkit-transform: translate3d(-100%, 0, 0);transform: translate3d(-100%, 0, 0);
    }
    .current-month-html {
      -webkit-transform: translate3d(0, 0, 0);transform: translate3d(0, 0, 0);
    }
    .next-month-html {
      -webkit-transform: translate3d(100%, 0, 0);transform: translate3d(100%, 0, 0);
    }
    .dayThead {height: 40px;}
    .dayThead .dayTd {
      line-height: 40px;border: none;color: #2c9bb3;
    }
    .dayThead .dayTd.active {color: #e02d2d;}
    .dayTbody .dayTd:hover {box-shadow: inset 0px 0px 4px #47D5FF;}
    .dayTd {
      height: 100%;-webkit-box-flex: 1;-webkit-flex: 1; -ms-flex: 1;flex: 1;text-align: center;cursor: pointer;
    }
    .dayTd .currentDay { background-color: #fb0;}
    .dayTd .restDay {background-color: #fff0f0;}
    .pannel {
      position: fixed;width: 100%;top: 30%;left: 0px;text-align: center;line-height: 40px;height: 40px;
      background-color: rgba(227, 36, 85, 0.86);color: #ffffff;opacity: 0;display: none;-webkit-transition: opacity 300ms;transition: opacity 300ms;
    }
    @media only screen and (min- 701px) {
        .container{height:500px;}
    }
    @media only screen and (max- 700px) {
      .container {
        -webkit-box-orient: vertical; -webkit-box-direction: normal; -webkit-flex-direction: column; -ms-flex-direction: column;flex-direction: column;height:305px;
      }
      .container .aside {
        width: 100%;height: 30%; padding: 5px;
      }
      .container .main { width: 100%;height: 100%;}
      .bigTime {line-height: 1;font-size: 5.3rem !important;}
      .operator { display: none; }
      .datePicker { height: calc(100% - 10px);}
      .noliDate {
        display: -webkit-box;display: -webkit-flex;display: -ms-flexbox; display: flex;
        -webkit-box-pack: center;-webkit-justify-content: center;-ms-flex-pack: center;justify-content: center;
      }
      .noliDate p {margin: 0 10px;}
      .goodBad { display: none;}
    }
    .dateUlContainer {
      height: 100%;width: 100%;overflow: hidden;
    }
    .yearChoose,.monthChoose,.returnToday {
      display: inline-block;font-size: 0.7rem;margin-right: 10%;
    }
    .returnToday {
      background-color: #f2f2f2;border: 1px solid #999;padding: 2px 10px;cursor: default;
    }
    .timeChoose {
      width: 100%;display: -webkit-box;display: -webkit-flex;display: -ms-flexbox;display: flex;
      -webkit-box-pack: center;-webkit-justify-content: center;-ms-flex-pack: center;justify-content: center;padding: 0.5rem 20px;
    }
    .chooseContainer {
      position: relative;font-size: 0.7rem;color: #333;
    }
    .chooseContainer .buttonGroup {
      border: 1px solid #999;border-bottom-color: #d8d8d8;border-right-color: #d8d8d8;padding-left: 5px;line-height: 1;
    }
    .chooseContainer .buttonGroup span {
      display: inline-block;
    }
    .chooseContainer .buttonGroup span.yearTime,
    .chooseContainer .buttonGroup span.monthTime {
      margin: 0px 8px;
    }
    .chooseContainer .buttonGroup span.pullDown {
      width: 1.2rem;line-height: 1.2rem;cursor: default;text-align: center;border-left: 1px solid #d8d8d8;background-color: #f2f2f2;
    }
    .chooseContainer .pullSelect {
      display: none;width: 100%; position: absolute; z-index: 20; height: 432px;border: 1px solid #bbb;background: #fff;overflow-y: scroll;
    }
    .chooseContainer .pullSelect.open {
      display: block;
    }
    .chooseContainer .pullSelect ul {
      background-color: #fff;list-style: none;
    }
    .chooseContainer .pullSelect ul li {
      padding: 5px 10px;
    }
    .chooseContainer .pullSelect ul li:hover {
      cursor: default;background-color: #f2f2f2;
    }
    .buttonGroup.open ~ .pullSelect {
      display: block;
    }
    @media only screen and (min- 700px) {
      html {font-size: 21.33333333px !important;}
      .dateContain .bigTime { font-size: 9rem;}
    }
    @media only screen and (min- 800px) {
      html {font-size: 21.6px !important;}
      .dateContain .bigTime {font-size: 9rem;}
    }
    @media only screen and (min- 998px) {
      html {font-size: 25.6px !important;}
    }
    /*page css*/
    .div-yearmonth,.div-operate,.ul-operate{background-color: #449DED;text-align: center;color: #FFFFFF;}
    .div-yearmonth{height: 42px;line-height: 42px;font-size: 16px;}
    .div-yearmonth .mui-icon{font-size: 20px;}
    .spn-today{margin: 0 10px;}
    #timeNow{margin-left: 5px;}
    .div-operate{height:56px;line-height:56px;}
    .ul-operate{height:56px;width:100%;}
    .ul-operate a{height:56px;width:25%;}
    .ul-operate a p{height:28px;color:#ffffff;line-height:22px;}
    .ul-operate a p:first-child{line-height:36px;}
    #container{margin-top:8px;}
    .mui-segmented-control .mui-control-item.mui-active:after {
        /*display: block;content: ''; 70%;border- 1px;border-style: solid;
        border-color: #ffffff;position: relative;bottom: 1px;margin: 0 auto;left: 0%;*/ /*细下划线*/
        content: '';width: 0;display: block;height: 0;bottom: 1px;margin: 0 auto;
        border-right: 8px solid transparent;border-bottom: 8px solid #FFFFFF;border-left: 8px solid transparent;/*三角形*/
    }
    .dayTbody .dayTr .dayTd.attendance{background-color:#F2F9FF;}
    .dayTbody .dayTr .dayTd.actualAttendance{background-color:#F2F9FF;}
    .dayTbody .dayTr .dayTd.beLate{background-color:#FFE1E1;}
    .dayTbody .dayTr .dayTd.leaveEarly{background-color:#FFF1D4;}
    .dayTbody .dayTr .dayTd.attendance.date-selected,.dayTbody .dayTr .dayTd.actualAttendance.date-selected,
    .dayTbody .dayTr .dayTd.beLate.date-selected,.dayTbody .dayTr .dayTd.leaveEarly.date-selected
    {
        background-color:#47D5FF;
    }
    .dayTbody .dayTr .dayTd.attendance.date-current,.dayTbody .dayTr .dayTd.actualAttendance.date-current,
    .dayTbody .dayTr .dayTd.beLate.date-current,.dayTbody .dayTr .dayTd.leaveEarly.date-current
    {
        background-color:#fb0;
    }
    .dayTbody .dayTr .dayTd.date-next,
    .dayTbody .dayTr .dayTd.date-prev
    /*.dayTbody .dayTr .dayTd.date-next.date-selected,
    .dayTbody .dayTr .dayTd.date-prev.date-selected*/
    {
        background-color:#fff;color:#bfbfbf;
    }
    .dayTbody .dayTr .dayTd.date-next.date-selected,
    .dayTbody .dayTr .dayTd.date-prev.date-selected
    {
        background-color:#47D5FF;color:#fff;
    }
    /*.dayTbody .dayTr .dayTd.date-next.date-selected span:first-child,.dayTbody .dayTr .dayTd.date-prev.date-selected span:last-child{
        color:#bfbfbf !important;
    }*/
    .date-next .dayNumber i.fl,.date-prev .dayNumber i.fl
    {
    display:none;
    }
    .dayNumber i.fl{font-size:12px;margin-top: -5px;margin-right: 10px;line-height: 0.8;position: absolute;display: block;}
    .font-warning{color:#FBD06B;}
    .font-danger{color:#FA6768;}
    .mui-scroll-wrapper.timeline{top:505px;}
    .emptyinfo{margin-top:10px;}
    .emptyinfo span.mui-icon{margin-bottom: 15px;}
    @media only screen and (max-height: 568px) {
    .emptyinfo {margin-top: 0px;}
    .emptyinfo span.mui-icon{font-size: 36px;margin-bottom: 5px;}
    }
    View Code

    注意事项

    • 忘记所有click的事件,通通采用tap事件代替,因为click会存在300ms的延时。
    • 不到万不得已,不要使用jquery,直接写原生js,因为jquery为了兼容各个版本的浏览器,写了许多的代码,而在手机上面的浏览器都是采用的Webkit内核,根本不需要考虑浏览器之间的兼容性问题,而且它能够很好的兼容css3特性。所以自然而然原生js的性能非常高,同时,你也不需要担心写js代码会很麻烦,HBuilder强大的智能提示和快捷键以及代码自动生成能力会让你写js快速如飞。
    • 能用vue.js就不要用angular,同vue.js比起来angular实在是太重,而且语法相对来说没那么优雅,学习曲线更是没那么平缓,做app对性能的要求是非常苛刻的。
    • 尽量不要使用位图,而是采用矢量图,因为矢量图渲染速度快,而且在不同分辨率下面不失真。
    • 矢量图图标,可以去阿里矢量库中查找,如果实在找不到,可以自己用AI做图标,然后生成svg格式,再上传到阿里矢量库中,最后统一打包下载下来,这样的话会把所有的矢量图标合成一张图片,减少文件数,还有,下载下来的文件中只需要保留iconfont.ttf和iconfont.css文件,因为我们只需要在移动端使用,记得修改iconfont.css文件去掉无用的引用。精简、极致。
    • HBuilder不要同时打开太多的项目,否则会很卡,而且HBuilder的错误智能感知比较弱,代码格式化也不够优雅,这些缺陷可以同时使用VS来解决(作为一名.net老鸟,吐血推荐的宇宙最强IDE),即同时用HBuilder和VS打开项目,用HBuilder写代码,VS进行格式化代码和语法查错,但是在切换IDE之前要记得保存代码,否则可能会造成代码覆盖,切记!
    • 能采用真机调试就不要用模拟器,原因还是速度!高效。

    作为一个后台开发人员来说,写js还不是最痛苦的,最痛苦的是调css样式,尤其是还需要兼容iso和android以及不同的移动设备,更要命的是不同的css样式写法,同样的效果,渲染速度还不一样......

    项目开发完成之后,我会将前端代码开源,目前还在开发中,敬请关注!

    关于更多MUI跨平台开发的资料,可以参考我的上一篇文章:MUI开发大全

    其它部分页面参考:2017-11-1 今天完成的界面,包括js交互实现

    最后,无可避免的,我花了大半天做的东西不符合客户需求...无语...重新改造...

  • 相关阅读:
    使用golang访问kubebernetes
    使用 Rancher 管理现有 Kubernetes 集群
    Running powershell scripts during nuget package installation and removal
    How to Create, Use, and Debug .NET application Crash Dumps in 2019
    寻找写代码感觉(一)之使用 Spring Boot 快速搭建项目
    Selenium+Java之解决org.openqa.selenium.InvalidArgumentException: invalid argument报错问题
    Selenium环境搭建
    关于Xpath定位方法知道这些基本够用
    Web自动化之浏览器启动
    【翻译】编写代码注释的最佳实践
  • 原文地址:https://www.cnblogs.com/jiekzou/p/7822536.html
Copyright © 2011-2022 走看看