Authored by 陈峰

秒杀列表页前端和交互开发结束

... ... @@ -14,13 +14,85 @@ const headerModel = require('../../../doraemon/models/header');
const _index = (req, res, next) => {
let headerData = headerModel.setNav({
navTitle: '秒杀活动',
navBtn: true
navBtn: true,
});
let result = {};
let result = {
products: [{
id: 1,
now: true
},{
id: 2,
wait: true
},{
id: 1,
over: true
},{
id: 1,
chance: true
}],
navs: [{
day: '2016/09/1',
time: '12:00',
over: true
}, {
day: '2016/09/1',
time: '12:00',
over: true
}, {
day: '2016/09/2',
time: '12:00',
over: true
}, {
day: '2016/09/2',
time: '12:00',
over: true
}, {
day: '2016/09/09',
time: '12:00',
over: true
}, {
day: '2016/09/09',
time: '17:25',
now: true
}, {
day: '2016/09/09',
time: '17:26',
wait: true
}, {
day: '2016/09/09',
time: '17:27',
wait: true
}, {
day: '2016/09/09',
time: '17:28',
last: true,
wait: true
}]
};
var hbsHelper = {
helpers: {
statusClass: (nav) => {
if (nav.over) {
return 'over';
} else if(nav.now) {
return 'now';
} else if(nav.wait) {
return 'wait';
} else {
return '';
}
}
}
}
res.render('seckill', Object.assign({
pageHeader: headerData
}, result));
pageHeader: headerData,
pageFooter: true,
width750: true,
times: 12
}, result, hbsHelper));
}
module.exports = {
... ...
<nav class="nav-list">
<ul>
<li>&nbsp;</li>
<li>&nbsp;</li>
<li>测试1</li>
<li>测试2</li>
<li>测试3</li>
<li>测试4</li>
<li>测试5</li>
<li>测试6</li>
<li>测试7</li>
<li>测试8</li>
<li>测试9</li>
<li>测试10</li>
<li>&nbsp;</li>
<li>&nbsp;</li>
</ul>
</nav>
\ No newline at end of file
<div class="seckill-list">
{{> seckill/nav}}
<div class="tips">您只有在详情页使用立即购买,才能享受秒杀价</div>
<div class="product-list">
{{# products}}
{{> seckill/product}}
{{/products}}
</div>
</div>
... ...
<nav class="nav-list">
<ul class="nav-ul hide">
{{# navs}}
<li class="time-item {{# if now}}focus{{/if}} {{statusClass this}} {{# if @last}}last{{/if}}">
<input type="hidden" name="" class="date" value="{{day}} {{time}}">
<div class="normal">
<p class="time">{{time}}</p>
<p class="status tip-over">已开抢</p>
<p class="status tip-now">抢购中</p>
<p class="status tip-wait">即将开抢</p>
</div>
<div class="selected">
<p class="time">
<span>{{time}}</span>
<span class="status tip-over">已开抢</span>
<span class="status tip-now">抢购中</span>
<span class="status tip-wait">即将开抢</span>
</p>
<div class="status info-over">
<p>还有商品可以继续抢购</p>
</div>
<div class="status info-now">
<div class="last-info">
<p class="status tip-over">已开抢</p>
<p class="status tip-now">抢购中</p>
<p class="status tip-wait">即将开抢</p>
</div>
<div class="last-count-down">
<p class="countdown">剩余:<i class="tick hour">00</i><i class="tick minute">00</i><i class="tick second">00</i></p>
</div>
</div>
<div class="status info-wait">
<p class="countdown">距开抢:<i class="tick hour">00</i><i class="tick minute">00</i><i class="tick second">00</i></p>
</div>
</div>
</li>
{{/navs}}
</ul>
</nav>
\ No newline at end of file
... ...
<a href="#" class="item">
<div class="item-img">
<img src="//img10.static.yhbimg.com/goodsimg/2016/09/06/16/010f4203952bfb27f121a8778421c14f97.jpg?imageView/2/w/235/h/314" alt="">
</div>
<div class="item-info">
<div class="item-title">
影时光Mtime 联盟之剑手机壳iPhone6/6s
</div>
{{# if wait}}
<div class="item-price">
<ins>¥99</ins><del>¥234</del>
</div>
{{/if}}
<div class="item-foot">
{{# if wait}}
<div class="item-time"><span><i class="iconfont">&#xe603;</i>8月31日 19:00开始</span></div>
{{else}}
<div class="item-price">
<ins>¥99</ins><del>¥234</del>
</div>
{{/if}}
<div class="item-button">
{{# if chance}}
<button class="btn btn-chance">还有机会</button>
{{else if over}}
<span class="old-price">还可以原价购买</span>
<button class="btn btn-over">已抢光</button>
{{else}}
<button class="btn btn-buy">去抢购</button>
{{/if}}
</div>
</div>
</div>
</a>
\ No newline at end of file
... ...
... ... @@ -8,21 +8,169 @@
var $ = require('yoho-jquery'),
IScroll = require('yoho-iscroll');
iScroll = new IScroll($('.nav-list')[0], {
scrollX: true,
scrollY: false,
tap: true,
eventPassthrough: true,
preventDefault: true
});
iScroll.on('scrollStart', function () {
$('.nav-list').addClass('srolling');
});
iScroll.on('scrollEnd', function () {
if ($('.nav-list').hasClass('srolling')) {
$('.nav-list').removeClass('srolling')
iScroll.scrollTo(-200, 0, 400, IScroll.utils.ease.elastic);
}
var times = $('.nav-ul>li').length,
startX = 0,
timeWidth = 0,
focusTimeWidth = 0,
iScroll;
/**
* [初始化时间段]
*/
function initNav() {
timeWidth = ($('.nav-ul>li:not(.focus)').width() + 1);
focusTimeWidth = ($('.nav-ul>li.focus').width() + 1);
$('.nav-ul').width((times - 1) * timeWidth + focusTimeWidth).removeClass('hide');
//只有时间段大于3个才需要定位
if ($('.nav-ul>li').length > 3 && $('.nav-ul>li.focus').length) {
startX = (0 - ($('.nav-ul>li.focus').index()-1)*timeWidth);
}
if (iScroll) {
iScroll.destroy();
}
iScroll = new IScroll($('.nav-list')[0], {
scrollX: true,
scrollY: false,
startX: startX,
tap: true,
eventPassthrough: true,
preventDefault: true,
bounceTime: 400,
bounceEasing: {
style: 'cubic-bezier(0.333333, 0.666667, 0.666667, 1)'
}
});
registerScrollEvents(iScroll);
}
/**
* [注册iscroll事件,滑动停止时判断位置自动选中居中时间段]
*/
function registerScrollEvents(iScroll) {
iScroll.on('scrollStart', function () {
$('.nav-list').addClass('srolling');
});
iScroll.on('scrollEnd', function () {
//避免死循环
if ($('.nav-list').hasClass('srolling')) {
$('.nav-list').removeClass('srolling');
var offsetLeft = this.x - $(window).width()/2;
for (var i = 0; i < $('.nav-ul>li').length; i++) {
offsetLeft += $('.nav-ul>li').eq(i).width();
if (offsetLeft >= 0) { //判断选中时间段
selectTime($('.nav-ul>li').eq(i));
break;
}
}
}
});
}
/**
* [选中时间段]
*/
function selectTime(el) {
$('.nav-ul>li').removeClass('focus');
var index = $(el).index();
$(el).addClass('focus');
//点击切换时遇到首尾特殊处理选中时间段位置,大于3个才需要滑动选中
if ($('.nav-ul>li').length > 3) {
if (index === 0) {
iScroll.scrollTo(0, 0, 400);
} else if (index === $('.nav-ul>li').length - 1) {
iScroll.scrollTo(0 - $('.nav-ul').width() + timeWidth * 2 + focusTimeWidth, 0, 400);
} else {
iScroll.scrollTo((0 - (index-1)*timeWidth), 0, 400);
}
}
if ($(el).hasClass('now') || $(el).hasClass('wait')) {
//初始化倒计时并开始计时
initTick(el);
}
}
$('.nav-ul>li').click(function () {
selectTime(this);
});
/**
* [刷新状态]
* @param {[type]} el [description]
* @return {[type]} [description]
*/
function refreshList(el) {
//刷新时间段状态
$('.nav-ul>li').each(function () {
$(this).removeClass('now over wait');
var time = new Date($(this).find('input.date').val());
var nowTime = new Date();
if (nowTime > time) { //当前时间大于这个时间段,已经开始和即将开始两种情况
if ($(this).next('.time-item').length) {
var nextTime = new Date($(this).next().find('input.date').val());
if (nowTime < nextTime) { //下一个时间段与当前时间来区别是否正在抢购
$(this).addClass('now');
} else {
$(this).addClass('over');
}
} else { //大于这个时间段但是后面没有秒抢时间端了,则依然显示抢购中
$(this).addClass('now');
}
} else if (!$(this).hasClass('nothing')) {
$(this).addClass('wait');
}
})
//刷新列表状态
console.log('刷新啊')
}
/**
* [初始化倒计时]
*/
var currentTick;
function initTick(el) {
if (currentTick) {
clearTimeout(currentTick);
}
var time;
var nowTime = Date.parse(new Date()) / 1000;
var offsetTime;
if ($(el).hasClass('now')) {
time = Date.parse(new Date($(el).next().find('input.date').val())) / 1000;
} else {
time = Date.parse(new Date($(el).find('input.date').val())) / 1000;
}
offsetTime = time - nowTime;
startTick(el, offsetTime);
}
/**
* [开始倒计时]
*/
function startTick(el, offsetTime) {
var hour = parseInt(offsetTime / (60 * 60), 10);
var minute = parseInt(offsetTime % (60 * 60) / 60, 10);
var second = offsetTime % 60;
$(el).find('.tick.hour').text(hour < 0 ? '00': (hour<10?('0'+hour):hour));
$(el).find('.tick.minute').text(minute < 0 ? '00': (minute<10?('0'+minute):minute));
$(el).find('.tick.second').text(second < 0 ? '00': (second<10?('0'+second):second));
if (offsetTime <= 0) { //结束倒计时刷新状态
refreshList(el);
} else {
setTimeout(function() {
startTick(el, --offsetTime);
}, 1000);
}
}
$(window).resize(function() {
initNav();
})
initNav();
var focus = $('.nav-ul>li.focus');
if (focus.length && (focus.hasClass('now') || focus.hasClass('wait'))) {
initTick($('.nav-ul>li.focus'));
}
}())
\ No newline at end of file
... ...
.seckill {
.seckill-times{
height: 3.4rem;
border-top: 1px solid #e0e0e0;
border-bottom: 1px solid #e0e0e0;
height: 119px;
border-top: 1px solid #e1e1e1;
border-bottom: 1px solid #e1e1e1;
.time-item {
float: left;
}
... ...
... ... @@ -10,7 +10,6 @@
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
html,
body {
width: 100%;
... ... @@ -18,6 +17,15 @@ body {
font-family: helvetica, Arial, "黑体";
line-height: 1.4;
}
.width750 {
font-size: 28px;
.main-wrap {
max-width: 750px;
}
.good-failure {
background-size: 155px !important;
}
}
button,
input,
... ...
.width750 {
.yoho-footer {
font-size: 28px;
}
.op-row {
padding: 0 35px;
height: 140px;
line-height: 140px;
.user-name {
margin-right: 1.17em;
margin-left: 0.35em;
max-width: 234px;
}
.back-to-top {
right: 47px;
}
.sep-line {
margin: 0 0.35em;
}
}
.copyright {
height: 140px;
line-height: 140px;
}
}
.yoho-footer {
position: relative;
width: 100%;
... ...
... ... @@ -10,7 +10,36 @@
font-size: 20PX;
line-height: 90px;
}
.width750 {
.yoho-header {
height: 105px;
line-height: 105px;
.nav-back {
left: 12px;
width: 105px;
height: 105px;
line-height: 105px;
}
.nav-home {
right: 12px;
width: 105px;
height: 105px;
line-height: 105px;
}
.nav-btn {
right: 12px;
width: 105px;
height: 105px;
line-height: 105px;
}
.nav-title {
margin-right: 117px;
margin-left: 117px;
font-size: 42px;
font-weight: normal;
}
}
}
.yoho-header {
position: relative;
z-index: 1;
... ... @@ -76,6 +105,18 @@
}
}
.width750 {
.system-update {
height: 105px;
line-height: 105px;
.system-header {
font-size: 70px;
}
span {
font-size: 94px;
}
}
}
.system-update {
display: none;
overflow: hidden;
... ... @@ -106,6 +147,24 @@
}
}
.width750 {
.homebuttom {
height: 105px;
ul {
padding-top: 14px;
li {
i {
margin-bottom: 9px;
}
span {
line-height: 47px;
font-size: 16px;
}
}
}
}
}
.homebuttom {
position: relative;
z-index: 2;
... ...
... ... @@ -14,7 +14,19 @@
opacity: 1;
}
}
.width750 {
.loading {
margin-top: -23px;
margin-left: -70px;
width: 140px;
height: 47px;
> div {
margin: 5px;
width: 35px;
height: 35px;
}
}
}
.loading-mask {
position: fixed;
top: 0;
... ...
@import "nav";
\ No newline at end of file
@import "nav";
@import "product";
@import "seckill";
\ No newline at end of file
... ...
.nav-list {
width: auto;
ul {
.seckill-list {
.nav-list {
background-color: #fff;
width: auto;
overflow: hidden;
white-space: nowrap;
display: table;
li{
width: 4rem;
height: 2rem;
border: solid 1px #ccc;
display: inline-block;
border-top: solid 1PX #e1e1e1;
border-bottom: solid 1PX #e1e1e1;
height: 119px;
ul {
width: auto;
overflow: hidden;
height: 100%;
padding-top: 20px;
li{
width: 226px;
height: 79px;
border-right: solid 1PX #e1e1e1;
text-align: center;
float: left;
$status-list: over, now, wait;
@each $status in $status-list {
&.$(status) {
.tip-$(status),
.info-$(status) {
display: initial;
}
}
}
&.last {
.last-info {
display: block;
},
.last-count-down {
display: none
}
}
.status,
.last-info {
display: none;
}
p {
font-size: 22px;
}
&:last-child {
border: none;
}
&.focus {
width: 300px;
.selected {
display: block;
}
.normal {
display: none;
}
}
.selected {
display: none;
color: #d0021b;
height: 79px;
}
.normal {
display: block;
height: 79px;
}
.time {
font-size: 30px;
span {
margin-right: 5px;
}
}
.tick {
font-size: 20px;
background-color: #d60117;
color: #fff;
margin-left: 10px;
border-radius: 3PX;
padding-left: 5px;
padding-right: 5px;
}
}
}
}
}
\ No newline at end of file
... ...
.seckill-list {
.product-list {
background-color: #fff;
.item {
padding: 20px 30px;
display: -webkit-box;
border-bottom: solid 1PX #e1e1e1;
&:first-child {
border-top: solid 1PX #e1e1e1;
}
.item-img {
width: 152px;
margin-right: 30px;
img {
width: 100%;
}
}
.item-info {
-webkit-box-flex: 1;
position: relative;
min-height: 202px;
.item-title {
font-size: 28px;
color: #444;
}
.item-price {
margin-top: 15px;
ins {
color: #d0021b;
font-size: 34px;
text-decoration: none;
margin-right: 10px;
}
del {
font-size: 20px;
color: #000;
color: rgb(176, 176, 176);
text-decoration: none;
}
}
.item-foot {
position: absolute;
left: 0px;
right: 0px;
bottom: 0px;
display: -webkit-box;
.item-price {
-webkit-box-flex: 1;
}
.item-time {
-webkit-box-flex: 1;
font-size: 22px;
padding-top: 28px;
-webkit-box-align: end;
i {
margin-right: 5px;
color: #b0b0b0;
}
span {
color: #b0b0b0;
}
}
.item-button {
width: 200px;
text-align: right;
.btn {
width: 155px;
height: 60px;
color: #fff;
background-color: #d0021b;
border-radius: 3PX;
border: none;
font-size: 28px;
&.btn-buy {
background-color: #d0021b;
}
&.btn-over {
background-color: #b2b2b2;
}
&.btn-chance {
background-color: #fff;
border: solid 1PX #454545;
color: #454545;
}
}
.old-price {
font-size: 20px;
color: #d0021b;
line-height: 30px;
}
}
}
}
}
}
}
\ No newline at end of file
... ...
.seckill-list {
background-color: #f0f0f0;
.tips {
height: 60px;
line-height: 60px;
font-size: 24px;
color: #b0b0b0;
padding-left: 30px;
padding-right: 30px;
}
}
\ No newline at end of file
... ...