类似携程,飞猪机票列表滚动的日期带价格

近期在优化我们公司的机票查询的价格日历(跟携程,飞猪的机票列表类似),之前是将所有切换的日期全部展示在网页中,由于默认查询日期是一年,会导致页面上存在大量的<li>,假如哪天产品要求日期默认是10年呢,估计页面要卡死了.

优化结果先看下最终的效果图:

可以看到以下两点:
1.不管怎么滚动,下面的<li>数量永远是固定的,不会随着滚动日期的增加 而累加<li>的数量,大大提高了页面的性能
2.点击了日期后,请求当天的价格,不替换<li>的情况下将"查看价格"赋值为具体的金额

技术支持:
对日期的处理主要使用的是moment.js

好了话不多说,上代码:

首先对日期做处理,设置了初始日期和截止日期,会返回这两个日期之间所有的日期,另外还会补齐已经过期的时间,和不可选择的时间,如果用户设置了当前日期,也会有标识出来,具体代码如下(下面代码要使用moment.js):

// 只负责处理日期,不负责处理业务
/*返回某时间段的所有日期数据,并格式化,并根据是否今天还是明天还是后天加了classname*/
var dateJson = []

function Calendar() {
    this.settings = {
        startDate: '2019-05-10', // 开始时间
        endDate: '2019-10-15',// 结束时间
        dateJson: dateJson, // 日期上的标识数据,class名字要和这个标识字段一摸一样,例如json里面的“折”是discount,那么css名字也叫.discount
        defaultSelectDate: ['2019-07-02', '2019-07-09'] // 选中的日期
    }
}

Calendar.prototype.init = function (opt) {
    $.extend(this.settings, opt);
    return (this.getAllDate(this.settings.startDate, this.settings.endDate));
}

Calendar.prototype.pushTag = function (yearMonthDay) {
    var tags = {};
    for (var i = 0; i < this.settings.dateJson.length; i++) {
        if (moment(yearMonthDay).format('x') === moment(this.settings.dateJson[i].date).format('x')) {
            for (var key in this.settings.dateJson[i]) {
                tags[key] = this.settings.dateJson[i][key];
            }
            break;
        }
    }
    return tags;
}
Calendar.prototype.setClass = function (start, end, i) { //根据日期给div设置样式
    var className = '',daytype='';
    if (i >= moment(start).format('x') && i <= moment(end)) { // 是否在开始和结束之间
        className = 's_day';daytype='s_day';
        if (moment(i).format('YYYY/MM/DD') === moment().format('YYYY/MM/DD')) { // 今天
            className += ' s_today';
        }
        $.each(this.settings.defaultSelectDate, function (index, item) { // defaultSelectDate
            if (moment(i).format('YYYY/MM/DD') === moment(item).format('YYYY/MM/DD')) {
                className += ' s_curday';
            }
        })
    } else {
        className = 's_pass';daytype='s_pass';
        if (moment(i).format('YYYY/MM/DD') === moment().format('YYYY/MM/DD')) {
            className += ' s_today';
        }
    }
    return {className:className,daytype:daytype};
}

Calendar.prototype.getAllDate = function (start, end) { // 获取两个日期间的所有日期数据
    var sd = Number(moment(start).startOf('month').format('x')); // 本月第一天
    var ed = Number(moment(end).endOf('month').format('x')); // 本月最后一天

    var dataObject = {};

    dataObject[sd] = {title: moment(start).format('YYYY年MM月'), date: []} // 初始第一个月
    // console.log( moment(sd).weekday())
    for (var w = 0; w < moment(sd).weekday(); w++) { // 对本月一号之前的周几补全。
        dataObject[sd].date.push({year: '', month: '', day: '', week: w});// 如果当前月份没有存储当前天数用的数组,就创建一个空数组,如果有,就向里面添加一个空对象; (空对象是用来占位置的,用来填充月份前面的空白)
    }
    for (var i = sd; i <= ed;) {
        var firstDay = Number(moment(i).startOf('month').format('x')); // 当月第一天;--作为每个月的唯一标示

        if (moment(i).format('x') === moment(moment(i).startOf('month').format('YYYY-MM-DD')).format('x') && i !== sd) { // 如果是当月的第一天,添加下个月的数据
            //   console.log(i, sd)
            var op = {
                title: moment(i).add(1, 'days').format('YYYY年MM月'), // 下个月的第一天
                date: []
            }
            for (var w = 0; w < moment(i).weekday(); w++) { // 对本月一号之前的周几补全。
                op.date.push({year: '', month: '', day: '', week: w});// 如果当前月份没有存储当前天数用的数组,就创建一个空数组,如果有,就向里面添加一个空对象; (空对象是用来占位置的,用来填充月份前面的空白)
            }
            dataObject[i] = op;
        }

        //根据日期给div设置样式
        var className = this.setClass(start, end, i).className;
        var daytype = this.setClass(start, end, i).daytype;
        var tag = this.pushTag(moment(i).format('YYYY/MM/DD')); // 折扣,休息等信息
        var option = {
            year: moment(i).format('YYYY'),
            month: moment(i).format('MM'),
            day: moment(i).format('DD'),
            week: moment(i).weekday(),
            classname: className,
            daytype: daytype,
            tags: tag,
            date: moment(i).format('YYYY/MM/DD')
        }
        dataObject[firstDay].date.push(option);
        i = Number(moment(i).add(1, 'days').format('x')); // 下次赋值
    }
    return dataObject;
}

运行下面这段代码试试: 

var c1 = new Calendar();
 var priceData = [
            {date: '2019-02-11', price: '100'},
            {date: '2019-02-12', price: '100', rest: '休'},
            {date: '2019-02-13', price: '100', discount: '折'}]
console.log(c1.init({
            startDate: '2019-02-06',
            endDate: '2019-04-22',
            defaultSelectDate: ['2019-02-09'],
            dateJson: priceData
        }))

结果:
1.默认是从周日开始排,2019-02-06是周五,所以前面会加5个空的年月日,
2.设置的初始日期是2019-02-06,所以2019-02-06之前和2019-04-22之后的日期都会加上s_pass的classname标识不可用日期,用以区分样式的,在2019-02-06到2019-04-22之前的日期,则都会加上s_day,表示可用日期,当前日期2019-02-09会加上s_curday
3.如果有json数据,tags里面会会带上来,展示大页面上的时候可以根据tags里面的key设置不同的样式 

得到了日期数据,接下来就是滚动的代码:

// 只负责滚动的逻辑,不负责业务
function setLodaDateSwrap() {
    this.CalendarBox = null;
    this.leftNum = null;
    this.rightNum = null;
    this.settings = {
        step:2, // 暂时没用
        fTime:3, // 暂时没用
        Calendar: 'ul',
        prev: '.last-month',
        next: '.next-month',
        prevClick:function(){},
        nextClick:function(){},
    }
}
setLodaDateSwrap.prototype.init = function (obj, opt) {
    $.extend(this.settings, opt);

    var This = this;
    this.CalendarBox = obj;
     this.leftNum = -$(this.settings.Calendar).width() / 2;
    // this.leftNum = -this.settings.step*$(this.settings.Calendar).find('.dayprice').width();

    this.rightNum = 0;
    var prevStr = this.CalendarBox + ' ' + this.settings.prev;
    var nextStr = this.CalendarBox + ' ' + this.settings.next;
    $(document).on('click', prevStr, function () {
        if($(This.settings.Calendar).is(":animated")){
            return;
        }
        var callbackFn = null;
        // 返回布尔值,用来判断前进后退按钮是否禁用
        var scroolBool = This.settings.prevClick(function(callback){
            callbackFn = callback;
        });
        if(!scroolBool){return;}
        This.swrap(This.leftNum, This.rightNum,function(){
            if(callbackFn){callbackFn()}
        });
        This.scroolPrevBool = scroolBool;
    });
    $(document).on('click', nextStr, function () {
        if($(This.settings.Calendar).is(":animated")){
            return;
        }
        var callbackFn = null;
        var scroolBool = This.settings.nextClick(function(callback){
            callbackFn = callback;
        });
        if(!scroolBool){return;}
        This.swrap(This.rightNum, This.leftNum,function(){
            if(callbackFn){callbackFn()}
        });
    });
}
setLodaDateSwrap.prototype.swrap = function (num1, num2,callback) {
    var This = this;
    if (!$(this.settings.Calendar).is(':animated')) {
        $(this.settings.Calendar).css({ left: num1 });
        $(this.settings.Calendar).stop().animate({ left: num2 }, 500, function () {
            $(This.settings.Calendar).css({ left: 0 });
            if(callback){callback()}
        });
    }
}

 

滚动的功能做好了,然后就是滚动和日期结合由于涉及到html+css,代码较多,就不一一帖过来了,完整代码请戳https://github.com/slailcp/DatePriceScroll

像这种日期和滚动分开的好处还是很多的,例如下面这种日历形式的也可以做出来,:

 

 

 

 

 

 

 

 

 

 

 

 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值