第四步,写静态数据,细节优化。根据前面的分析,各个部分的容器都已经准备就绪,接着就该将各部分应该呈现的内容写入到对应的位置中去了,这一步代码会稍微多些。而且根据自己的需求,可能在某些判断逻辑上会略显不同,先看看我的示例代码吧:
var Utils = { // 格式化数字,小于10补前置0 prefixZero: function(num) { return num < 10 ? '0' + num : num; } }; function createTimeline(from, to) { var Timeline, f = typeof from === 'string' ? new Date(from.replace(/-/g, '/')) : from, t = typeof to === 'string' ? new Date(to.replace(/-/g, '/')) : to, timestamp = t - f, day = 24 * 60 * 60 * 1000, today = new Date(), miliStart = f.getTime(), dayCount = Math.floor(timestamp / day) + 1, // 计算时间轴上显示的总天数 offLeft = 12, // 初始日期左边距 offRight = 12, // 结束日期右边距 offDay = 20, // 日与日之间的间距 lineLength = dayCount * offDay + offLeft + offRight; // 计算时间轴的长度 var line = $(''), monthLabel, dayLabel, dayDiff, scaleLabel; line.css({width: lineLength, height: 134}); line.html('' + '' + '' + '' + ''); monthLabel = line.find('.J_MonthLabel'); dayLabel = line.find('.J_DayLabel'); dayDiff = line.find('.J_DayDiff'); scaleLabel = line.find('.J_ScaleLabel'); for (var i = 0; i < dayCount; i++) { var d = new Date(miliStart + i * day), left = i * offDay + offLeft, monthObj, dayObj, scaleObj; dayObj = $(''); dayObj.css('left', left - 9); dayObj.html(d.getDate()); // 如果【今天】在时间轴范围内,则强调显示 if (d.getFullYear() === today.getFullYear() && d.getMonth() === today.getMonth() && d.getDate() === today.getDate()) { dayObj.addClass('today'); } scaleObj = $(''); scaleObj.css('left', left); scaleObj.attr('data-date', d.getFullYear() + '/' + Utils.prefixZero(d.getMonth() + 1) + '/' + Utils.prefixZero(d.getDate())); // 在每月第一天的上方显示月份信息 if (d.getDate() === 1) { scaleObj.addClass('first-day'); monthObj = $(''); monthObj.css('left', left); monthObj.html(d.getFullYear() + '/' + Utils.prefixZero(d.getMonth() + 1)); monthLabel.append(monthObj); } dayLabel.append(dayObj); scaleLabel.append(scaleObj); } tw.html('').append(line); Timeline = { slider: line, monthLabel: monthLabel, dayLabel: dayLabel, dayDiff: dayDiff, scaleLabel: scaleLabel }; return Timeline; }
var serverData = { snapshotTimes: [{ date: '2016/06/01', content: 'JD618大促启动' }, { date: '2016/06/18', content: '京东618大促进行时' }, { date: '2016/09/15', content: '2016年中秋节放假' }] };
var data = serverData.snapshotTimes, tLen = data.length, tempDate, tlBegin, tlEnd; tlBegin = data[0].date; tempDate = new Date(data[tLen - 1].date); // 时间轴最后预留三个月空时段,保证时间轴的视觉效果美观 if (tempDate.getMonth() > 8) { tlEnd = (tempDate.getFullYear() + 1) + '/0' + ((tempDate.getMonth() + 3) % 11) + '/' + Utils.prefixZero(tempDate.getDate()); } else { tlEnd = tempDate.getFullYear() + '/' + Utils.prefixZero(tempDate.getMonth() + 4) + '/' + Utils.prefixZero(tempDate.getDate()); } // 根据服务端数据的起始日期,初始化时间轴 TL = createTimeline(tlBegin, tlEnd); // 根据日期,将事件触发器绑到对应刻度上 $.each(data, function(idx, d){ var sc = TL.scaleLabel.find('.J_Scale[data-date="' + d.date + '"]'), sct = sc.attr('data-date'), scArr = sct.split('/'); sc.addClass('has-snap').html('' + scArr[1] + '月' + scArr[2] + ''); });
function selectByDate(dateStr) { var ele = TL.scaleLabel.find('.J_Scale[data-date="' + dateStr.replace(/-/g, '/') + '"]'), nextEle = ele.nextAll('.has-snap').eq(0), nLast, nl, nw, today = new Date(), lastDate; if (!ele.length) { return; } nl = parseFloat(ele.css('left')); if (nextEle.length) { // 如果存在下一个有has-snap标记的元素 nLast = nextEle; lastDate = new Date(nLast.attr('data-date')); } else { // 如果已是最后一个有has-snap标记的元素 nLast = TL.scaleLabel.find('.J_Scale').last(); lastDate = new Date(nLast.attr('data-date')); // 如果最后一个刻度日期大于今天,则结束刻度设为今天,否则使用最后刻度 if (lastDate > today) { lastDate = today; nLast = TL.scaleLabel.find('.J_Scale[data-date="' + (today.getFullYear() + '/' + Utils.prefixZero(today.getMonth() + 1) + '/' + Utils.prefixZero(today.getDate())) + '"]'); } } // 这里是对选中某项后做一些其他业务,与本文关系不太大 if (!nextEle.length && lastDate !== today) { selDays.html(Math.floor((today - new Date(ele.attr('data-date'))) / (24 * 60 * 60 * 1000))); selRange.html(ele.attr('data-date').replace(/\//g, '-') + ' ~ ' + '今天'); nw = parseFloat(nLast.css('left')) - parseFloat(ele.css('left')) + 32; } else { selDays.html(Math.floor((new Date(nLast.attr('data-date')) - new Date(ele.attr('data-date'))) / (24 * 60 * 60 * 1000))); selRange.html(ele.attr('data-date').replace(/\//g, '-') + ' ~ ' + nLast.attr('data-date').replace(/\//g, '-')); nw = parseFloat(nLast.css('left')) - parseFloat(ele.css('left')); } viewFrame.attr('src', '/decorate/getSnapshotInfoByAppAndTime.html?appId=' + appId + '&snapshotTime=' + ele.attr('data-date').replace(/\//g, '-')); TL.scaleLabel.find('.active').removeClass('active'); ele.find('.J_SnapshotLink').addClass('active'); TL.dayDiff.css({left: nl, width: 0}); TL.dayDiff.animate({width: nw}, 300); }
tw.delegate('.J_TimeLine', 'mousedown', function(ev){ // 拖拽及回弹 var originX = ev.clientX, moveX = originX, delta = 0, originLeft = parseFloat(TL.slider.css('left')); if (TL.slider.width() < tw.width()) { return true; } TL.slider.data('moved', false); doc.bind('mousemove', function(ev){ moveX = ev.clientX; delta = moveX - originX; if (Math.abs(delta) > 10) { TL.slider.css('left', originLeft + delta + 'px'); } }); doc.bind('mouseup', function(ev){ doc.unbind('mousemove'); doc.unbind('mouseup'); if (Math.abs(delta) <= 10) { TL.slider.data('moved', false); } else { TL.slider.data('moved', true); } var tLeft = parseFloat(TL.slider.css('left')), tWidth = tw.width(); if (tLeft > 0) { TL.slider.animate({'left': 0}, 300, function(){}); } else if (Math.abs(tLeft) > TL.slider.width() - tWidth) { TL.slider.animate({'left': '-' + (TL.slider.width() - tWidth) + 'px'}, 300, function(){}); } }); }).delegate('.J_SnapshotLink', 'click', function(ev){ // 标签点击选中事件 if (TL.slider.data('moved')) { return false; } var _this = $(this), hrefArr = _this.attr('href').split('#'); selectByDate(hrefArr[1]); ev.preventDefault(); });