使用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 会出现头部空白部分,后面研究看看能不能解决
最终效果:
网友评论