使用swiper + angular+jquery实现上下滑动的日历

使用angular1+swiper4 实现上下滑动的日历
实现思路:
当上下滑动时,使用jquery写入当前日期到日历上去,最初的想法是使用swiper的loop属性,来实现,但是实际使用下来之后发现体验并不好,并且会存在一些BUG,所以就改用VirtualSlide来实现.代码如下:

html部分

<div ng-controller="calendarController">
  <div class="swiper-container swiper-container-horizontal swiper-container-ios">
        <div class="swiper-wrapper">
        </div>
  </div>
</div>

js部分

angular.module('app', []).controller('calendarController',function ($scope,$compile) {
    var currentIndex = 0;
    var compiledArray = [];// 已经被编译过的dom的index
    // 定义每个月的日历,最大是42个
    $scope.monthCalendar = new Array(42);
 
    var mySwiper = {};
    angular.element(document).ready(function () {
        var totalSlides = 1000; // 默认定义1000个slides
        var initialSlide = totalSlides / 2;
        mySwiper = new Swiper('.swiper-container', {
            slidesPerView: 1,
            initialSlide: initialSlide,
            spaceBetween: 30,
            direction: 'vertical',
            height: 600,
            virtual: {
                slides: (function () {
                    var slides = [];
                    // 加载html
                    for (var i = 0; i < totalSlides; i += 1) {
                        var html = '<div lnk-slides class="weekday-container">\n' +
                            '                            <span ng-repeat="day in weekDays" ng-bind="day">\n' +
                            '                            </span>\n' +
                            '                        </div>\n' +
                            '                        <div class="day-item-container" ng-repeat="i in [0,1,2,3,4,5]">\n' +
                            '                            <span\n' +
                            '                                  class="day-item current-month-day" ng-click="selectCurrentDay($event)" ng-repeat="j in weekDays"></span>\n' +
                            '                        </div>';

                        slides.push(html);
                    }
                    return slides;
                }())
            },
            on: {
                init: function () {
                    // 当Swiper初始化完成后,将默认的slide编译后加入到数组中
                    compiledArray.push(this.realIndex);
                    $compile(this.slides[1])($scope);
                    $scope.$apply();
                },
            },
        });

        // 当前选中slide的index
        // 用于控制上下滑动是否实际切换slide
        // 向上滑动
        mySwiper.on('slidePrevTransitionEnd', function () {
            if (currentIndex !== mySwiper.realIndex) {
                currentIndex = mySwiper.realIndex;
                // 未被angular编译的dom元素需要被编译后才能在angular的监听下
                if (!compiledArray.contains(mySwiper.realIndex)) {
                    compiledArray.push(mySwiper.realIndex);
                    $compile(this.slides[1])($scope);
                    $scope.$apply();
                }
                $scope.currentSelectedDate = new Date($scope.currentSelectedDate.getFullYear(), $scope.currentSelectedDate.getMonth() - 1, $scope.currentSelectedDate.getDate());
                $scope.getCalendar('prev', $scope.currentSelectedDate);
            }
        });
        // 向下滑动
        mySwiper.on('slideNextTransitionEnd', function () {
            // 已经切换了页签,则刷新日期及数据
            if (currentIndex !== mySwiper.realIndex) {
                // 未被angular编译的dom元素需要被编译后才能在angular的监听下
                if (!compiledArray.contains(mySwiper.realIndex)) {
                    compiledArray.push(mySwiper.realIndex);
                    $compile(this.slides[1])($scope);
                    $scope.$apply();
                }
                currentIndex = mySwiper.realIndex;
                $scope.currentSelectedDate = new Date($scope.currentSelectedDate.getFullYear(), $scope.currentSelectedDate.getMonth() + 1, $scope.currentSelectedDate.getDate());
                $scope.getCalendar('next', $scope.currentSelectedDate);
            }
        });
        // 加载完Swiper之后,默认显示今天的日期及数据
        $scope.getCalendar('today', $scope.currentSelectedDate);
    });

    /**
     * 创建日历数据
     */
    $scope.getCalendar = function (direction, currentSelectedMonthDate) {
        var year = ''; // 年份
        var month = '';// 月份
        // 用于存储数据的对象
        $scope.monthCalendar = [];
        // 获取年份和月份
        year = currentSelectedMonthDate.getFullYear();
        month = currentSelectedMonthDate.getMonth() + 1;
        // 获取当月的第一天
        var firstDate = new Date(year, month - 1, 1);
        // 获取当前slide下的子对象个数,默认是有42个
        var spans = $('.swiper-slide.swiper-slide-active .day-item-container .day-item');
        for (var i = 0; i < spans.length; i++) {
            // 获取个子对象对应的日期
            var date = new Date(year, month - 1, i + 1 - firstDate.getDay());
            var spanItem = $(spans[i]);
            // 非当月,则移除class
            if (date.getMonth() !== month - 1) {
                spanItem.removeClass('current-month-day');
            } else {
                // 日期数据
                var dateStr = dateFormat(date);
                // 如果是今天,则标红
                if (dateStr === dateFormat(new Date())) {
                    spanItem.addClass('today');
                }
            }
            $scope.monthCalendar[i] = dateStr;
            // 点击时需要用到的数据,所以直接加到属性上去
            spanItem.attr('current-date-data', dateStr);
            spans[i].innerText = dateFormat(date, 'MM-dd');
        }
    };
    $scope.selectCurrentDay = function ($event) {
        var target = $event.target;
        console.log($(target).attr('current-date-data'));
    };

    // 设置slides个数,用两个做循环,如果只使用一个,无法向下滚,估计是BUG..
    $scope.slides = [1, 2];
    // 默认初始化选中的日期为今天
    $scope.currentSelectedDate = new Date();
    $scope.weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']



    /**
     * 日期对象转为日期字符串
     * @param date 需要格式化的日期对象
     * @param sFormat 输出格式,默认为yyyy-MM-dd                         年:y,月:M,日:d,时:h,分:m,秒:s
     * @example  dateFormat(new Date())                                "2017-02-28"
     * @example  dateFormat(new Date(),'yyyy-MM-dd')                   "2017-02-28"
     * @example  dateFormat(new Date(),'yyyy-MM-dd hh:mm:ss')         "2017-02-28 09:24:00"
     * @example  dateFormat(new Date(),'hh:mm')                       "09:24"
     * @example  dateFormat(new Date(),'yyyy-MM-ddThh:mm:ss+08:00')   "2017-02-28T09:24:00+08:00"
     * @returns {string}
     */
    function dateFormat(date, sFormat) {
        if(isEmpty(sFormat)){
            sFormat = 'yyyy-MM-dd'
        }
        var time = {
            Year: 0,
            TYear: '0',
            Month: 0,
            TMonth: '0',
            Day: 0,
            TDay: '0',
            Hour: 0,
            THour: '0',
            hour: 0,
            Thour: '0',
            Minute: 0,
            TMinute: '0',
            Second: 0,
            TSecond: '0',
            Millisecond: 0
        };
        time.Year = date.getFullYear();
        time.TYear = String(time.Year).substr(2);
        time.Month = date.getMonth() + 1;
        time.TMonth = time.Month < 10 ? "0" + time.Month : String(time.Month);
        time.Day = date.getDate();
        time.TDay = time.Day < 10 ? "0" + time.Day : String(time.Day);
        time.Hour = date.getHours();
        time.THour = time.Hour < 10 ? "0" + time.Hour : String(time.Hour);
        time.hour = time.Hour < 13 ? time.Hour : time.Hour - 12;
        time.Thour = time.hour < 10 ? "0" + time.hour : String(time.hour);
        time.Minute = date.getMinutes();
        time.TMinute = time.Minute < 10 ? "0" + time.Minute : String(time.Minute);
        time.Second = date.getSeconds();
        time.TSecond = time.Second < 10 ? "0" + time.Second : String(time.Second);
        time.Millisecond = date.getMilliseconds();

        return sFormat.replace(/yyyy/ig, String(time.Year))
            .replace(/yyy/ig, String(time.Year))
            .replace(/yy/ig, time.TYear)
            .replace(/y/ig, time.TYear)

            .replace(/MM/g, time.TMonth)
            .replace(/M/g, String(time.Month))

            .replace(/dd/ig, time.TDay)
            .replace(/d/ig, String(time.Day))

            .replace(/HH/g, time.THour)
            .replace(/H/g, String(time.Hour))
            .replace(/hh/g, time.Thour)
            .replace(/h/g, String(time.hour))

            .replace(/mm/g, time.TMinute)
            .replace(/m/g, String(time.Minute))
            .replace(/ss/ig, time.TSecond)
            .replace(/s/ig, String(time.Second))
            .replace(/fff/ig, String(time.Millisecond))
    }

    function isEmpty(v) {
        if (v == null) {
            return true;
        }
        if (v == undefined) {
            return true;
        }
        if (v == "") {
            return true;
        }
        if (typeof v == "undefined") {
            return true;
        }
        switch (typeof v) {
            case 'date':
                return true;
            case 'undefined' :
                return true;
            case 'string' :
                if (v.trim().length === 0)
                    return true;
                break;
            case 'boolean' :
                if (!v)
                    return true;
                break;
            case 'number' :
                if (0 === v)
                    return true;
                break;
            case 'object' :
                if (null === v) {
                    return true;
                }
                else if (undefined !== v.length && v.length === 0) {
                    return true;
                }
                else {
                    return false;
                }
                break;
        }
        return false;
    };
});

Array.prototype.contains = function (obj) {
    var index = this.length;
    while (index--) {
        if (this[index] === obj) {
            return true;
        }
    }
    return false;
}

需要注意几点:
1.这里创建swiper对象,需要在angular的dom加载完成后再做,否则会报错
2.slide的高度现在是直接定成600px,在有些情况下是不合适的,所以可以根据屏幕宽高来动态设置,这里就不加了

css部分,用的是scss

.swiper-container {
    height: 100%;
  }
  .swiper-slide {
    text-align: center;
    font-size: 18px;
    background: #fff;
    width: 100%;
    height: 80%;
    flex-wrap: wrap;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    .weekday-container{
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      span{
        color: red;
      }
    }
    .day-item-container{
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      .day-item{

      }
    }
    span{
      display: inline-block;
      width: calc(100% /7);
      color:gray;
    }
    .today{
      color: red !important;
    }
    .current-month-day{
      color: green;
    }
  }

这个现在还存在着一点问题,就是未被加载过的VirtualSlide 会出现头部空白部分,后面研究看看能不能解决
最终效果:

calendar.gif
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351