Authored by 陈峰

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

@@ -14,13 +14,85 @@ const headerModel = require('../../../doraemon/models/header'); @@ -14,13 +14,85 @@ const headerModel = require('../../../doraemon/models/header');
14 const _index = (req, res, next) => { 14 const _index = (req, res, next) => {
15 let headerData = headerModel.setNav({ 15 let headerData = headerModel.setNav({
16 navTitle: '秒杀活动', 16 navTitle: '秒杀活动',
17 - navBtn: true 17 + navBtn: true,
  18 +
18 }); 19 });
19 - let result = {}; 20 + let result = {
  21 + products: [{
  22 + id: 1,
  23 + now: true
  24 + },{
  25 + id: 2,
  26 + wait: true
  27 + },{
  28 + id: 1,
  29 + over: true
  30 + },{
  31 + id: 1,
  32 + chance: true
  33 + }],
  34 + navs: [{
  35 + day: '2016/09/1',
  36 + time: '12:00',
  37 + over: true
  38 + }, {
  39 + day: '2016/09/1',
  40 + time: '12:00',
  41 + over: true
  42 + }, {
  43 + day: '2016/09/2',
  44 + time: '12:00',
  45 + over: true
  46 + }, {
  47 + day: '2016/09/2',
  48 + time: '12:00',
  49 + over: true
  50 + }, {
  51 + day: '2016/09/09',
  52 + time: '12:00',
  53 + over: true
  54 + }, {
  55 + day: '2016/09/09',
  56 + time: '17:25',
  57 + now: true
  58 + }, {
  59 + day: '2016/09/09',
  60 + time: '17:26',
  61 + wait: true
  62 + }, {
  63 + day: '2016/09/09',
  64 + time: '17:27',
  65 + wait: true
  66 + }, {
  67 + day: '2016/09/09',
  68 + time: '17:28',
  69 + last: true,
  70 + wait: true
  71 + }]
  72 + };
  73 + var hbsHelper = {
  74 + helpers: {
  75 + statusClass: (nav) => {
  76 + if (nav.over) {
  77 + return 'over';
  78 + } else if(nav.now) {
  79 + return 'now';
  80 + } else if(nav.wait) {
  81 + return 'wait';
  82 + } else {
  83 + return '';
  84 + }
  85 + }
  86 + }
  87 +
  88 + }
20 89
21 res.render('seckill', Object.assign({ 90 res.render('seckill', Object.assign({
22 - pageHeader: headerData  
23 - }, result)); 91 + pageHeader: headerData,
  92 + pageFooter: true,
  93 + width750: true,
  94 + times: 12
  95 + }, result, hbsHelper));
24 } 96 }
25 97
26 module.exports = { 98 module.exports = {
1 -<nav class="nav-list">  
2 - <ul>  
3 - <li>&nbsp;</li>  
4 - <li>&nbsp;</li>  
5 - <li>测试1</li>  
6 - <li>测试2</li>  
7 - <li>测试3</li>  
8 - <li>测试4</li>  
9 - <li>测试5</li>  
10 - <li>测试6</li>  
11 - <li>测试7</li>  
12 - <li>测试8</li>  
13 - <li>测试9</li>  
14 - <li>测试10</li>  
15 - <li>&nbsp;</li>  
16 - <li>&nbsp;</li>  
17 - </ul>  
18 -</nav>  
  1 +<div class="seckill-list">
  2 + {{> seckill/nav}}
  3 + <div class="tips">您只有在详情页使用立即购买,才能享受秒杀价</div>
  4 + <div class="product-list">
  5 + {{# products}}
  6 + {{> seckill/product}}
  7 + {{/products}}
  8 + </div>
  9 +</div>
  1 +<nav class="nav-list">
  2 + <ul class="nav-ul hide">
  3 + {{# navs}}
  4 + <li class="time-item {{# if now}}focus{{/if}} {{statusClass this}} {{# if @last}}last{{/if}}">
  5 + <input type="hidden" name="" class="date" value="{{day}} {{time}}">
  6 + <div class="normal">
  7 + <p class="time">{{time}}</p>
  8 + <p class="status tip-over">已开抢</p>
  9 + <p class="status tip-now">抢购中</p>
  10 + <p class="status tip-wait">即将开抢</p>
  11 + </div>
  12 + <div class="selected">
  13 + <p class="time">
  14 + <span>{{time}}</span>
  15 + <span class="status tip-over">已开抢</span>
  16 + <span class="status tip-now">抢购中</span>
  17 + <span class="status tip-wait">即将开抢</span>
  18 + </p>
  19 + <div class="status info-over">
  20 + <p>还有商品可以继续抢购</p>
  21 + </div>
  22 + <div class="status info-now">
  23 + <div class="last-info">
  24 + <p class="status tip-over">已开抢</p>
  25 + <p class="status tip-now">抢购中</p>
  26 + <p class="status tip-wait">即将开抢</p>
  27 + </div>
  28 + <div class="last-count-down">
  29 + <p class="countdown">剩余:<i class="tick hour">00</i><i class="tick minute">00</i><i class="tick second">00</i></p>
  30 + </div>
  31 + </div>
  32 + <div class="status info-wait">
  33 + <p class="countdown">距开抢:<i class="tick hour">00</i><i class="tick minute">00</i><i class="tick second">00</i></p>
  34 + </div>
  35 + </div>
  36 + </li>
  37 + {{/navs}}
  38 + </ul>
  39 +</nav>
  1 +<a href="#" class="item">
  2 + <div class="item-img">
  3 + <img src="//img10.static.yhbimg.com/goodsimg/2016/09/06/16/010f4203952bfb27f121a8778421c14f97.jpg?imageView/2/w/235/h/314" alt="">
  4 + </div>
  5 + <div class="item-info">
  6 + <div class="item-title">
  7 + 影时光Mtime 联盟之剑手机壳iPhone6/6s
  8 + </div>
  9 + {{# if wait}}
  10 + <div class="item-price">
  11 + <ins>¥99</ins><del>¥234</del>
  12 + </div>
  13 + {{/if}}
  14 +
  15 + <div class="item-foot">
  16 + {{# if wait}}
  17 + <div class="item-time"><span><i class="iconfont">&#xe603;</i>8月31日 19:00开始</span></div>
  18 + {{else}}
  19 + <div class="item-price">
  20 + <ins>¥99</ins><del>¥234</del>
  21 + </div>
  22 + {{/if}}
  23 +
  24 + <div class="item-button">
  25 + {{# if chance}}
  26 + <button class="btn btn-chance">还有机会</button>
  27 + {{else if over}}
  28 + <span class="old-price">还可以原价购买</span>
  29 + <button class="btn btn-over">已抢光</button>
  30 + {{else}}
  31 + <button class="btn btn-buy">去抢购</button>
  32 + {{/if}}
  33 + </div>
  34 + </div>
  35 + </div>
  36 +</a>
@@ -8,21 +8,169 @@ @@ -8,21 +8,169 @@
8 var $ = require('yoho-jquery'), 8 var $ = require('yoho-jquery'),
9 IScroll = require('yoho-iscroll'); 9 IScroll = require('yoho-iscroll');
10 10
11 - iScroll = new IScroll($('.nav-list')[0], {  
12 - scrollX: true,  
13 - scrollY: false,  
14 - tap: true,  
15 - eventPassthrough: true,  
16 - preventDefault: true  
17 - });  
18 - iScroll.on('scrollStart', function () {  
19 - $('.nav-list').addClass('srolling');  
20 - });  
21 - iScroll.on('scrollEnd', function () {  
22 - if ($('.nav-list').hasClass('srolling')) {  
23 - $('.nav-list').removeClass('srolling')  
24 - iScroll.scrollTo(-200, 0, 400, IScroll.utils.ease.elastic);  
25 - } 11 + var times = $('.nav-ul>li').length,
  12 + startX = 0,
  13 + timeWidth = 0,
  14 + focusTimeWidth = 0,
  15 + iScroll;
  16 +
  17 + /**
  18 + * [初始化时间段]
  19 + */
  20 + function initNav() {
  21 + timeWidth = ($('.nav-ul>li:not(.focus)').width() + 1);
  22 + focusTimeWidth = ($('.nav-ul>li.focus').width() + 1);
  23 +
  24 + $('.nav-ul').width((times - 1) * timeWidth + focusTimeWidth).removeClass('hide');
  25 + //只有时间段大于3个才需要定位
  26 + if ($('.nav-ul>li').length > 3 && $('.nav-ul>li.focus').length) {
  27 + startX = (0 - ($('.nav-ul>li.focus').index()-1)*timeWidth);
  28 + }
  29 + if (iScroll) {
  30 + iScroll.destroy();
  31 + }
  32 + iScroll = new IScroll($('.nav-list')[0], {
  33 + scrollX: true,
  34 + scrollY: false,
  35 + startX: startX,
  36 + tap: true,
  37 + eventPassthrough: true,
  38 + preventDefault: true,
  39 + bounceTime: 400,
  40 + bounceEasing: {
  41 + style: 'cubic-bezier(0.333333, 0.666667, 0.666667, 1)'
  42 + }
  43 + });
  44 + registerScrollEvents(iScroll);
  45 + }
  46 + /**
  47 + * [注册iscroll事件,滑动停止时判断位置自动选中居中时间段]
  48 + */
  49 + function registerScrollEvents(iScroll) {
  50 + iScroll.on('scrollStart', function () {
  51 + $('.nav-list').addClass('srolling');
  52 + });
  53 + iScroll.on('scrollEnd', function () {
  54 + //避免死循环
  55 + if ($('.nav-list').hasClass('srolling')) {
  56 + $('.nav-list').removeClass('srolling');
  57 + var offsetLeft = this.x - $(window).width()/2;
  58 + for (var i = 0; i < $('.nav-ul>li').length; i++) {
  59 + offsetLeft += $('.nav-ul>li').eq(i).width();
  60 + if (offsetLeft >= 0) { //判断选中时间段
  61 + selectTime($('.nav-ul>li').eq(i));
  62 + break;
  63 + }
  64 + }
  65 + }
  66 + });
  67 + }
  68 + /**
  69 + * [选中时间段]
  70 + */
  71 + function selectTime(el) {
  72 + $('.nav-ul>li').removeClass('focus');
  73 + var index = $(el).index();
  74 +
  75 + $(el).addClass('focus');
  76 + //点击切换时遇到首尾特殊处理选中时间段位置,大于3个才需要滑动选中
  77 + if ($('.nav-ul>li').length > 3) {
  78 + if (index === 0) {
  79 + iScroll.scrollTo(0, 0, 400);
  80 + } else if (index === $('.nav-ul>li').length - 1) {
  81 + iScroll.scrollTo(0 - $('.nav-ul').width() + timeWidth * 2 + focusTimeWidth, 0, 400);
  82 + } else {
  83 + iScroll.scrollTo((0 - (index-1)*timeWidth), 0, 400);
  84 + }
  85 + }
  86 +
  87 + if ($(el).hasClass('now') || $(el).hasClass('wait')) {
  88 + //初始化倒计时并开始计时
  89 + initTick(el);
  90 + }
  91 + }
  92 + $('.nav-ul>li').click(function () {
  93 + selectTime(this);
26 }); 94 });
  95 +
  96 +
  97 + /**
  98 + * [刷新状态]
  99 + * @param {[type]} el [description]
  100 + * @return {[type]} [description]
  101 + */
  102 + function refreshList(el) {
  103 + //刷新时间段状态
  104 + $('.nav-ul>li').each(function () {
  105 + $(this).removeClass('now over wait');
  106 + var time = new Date($(this).find('input.date').val());
  107 + var nowTime = new Date();
  108 + if (nowTime > time) { //当前时间大于这个时间段,已经开始和即将开始两种情况
  109 + if ($(this).next('.time-item').length) {
  110 + var nextTime = new Date($(this).next().find('input.date').val());
  111 + if (nowTime < nextTime) { //下一个时间段与当前时间来区别是否正在抢购
  112 + $(this).addClass('now');
  113 + } else {
  114 + $(this).addClass('over');
  115 + }
  116 + } else { //大于这个时间段但是后面没有秒抢时间端了,则依然显示抢购中
  117 + $(this).addClass('now');
  118 + }
  119 + } else if (!$(this).hasClass('nothing')) {
  120 + $(this).addClass('wait');
  121 + }
  122 + })
  123 + //刷新列表状态
  124 + console.log('刷新啊')
  125 + }
  126 + /**
  127 + * [初始化倒计时]
  128 + */
  129 + var currentTick;
  130 + function initTick(el) {
  131 + if (currentTick) {
  132 + clearTimeout(currentTick);
  133 + }
  134 + var time;
  135 +
  136 + var nowTime = Date.parse(new Date()) / 1000;
  137 + var offsetTime;
  138 + if ($(el).hasClass('now')) {
  139 + time = Date.parse(new Date($(el).next().find('input.date').val())) / 1000;
  140 + } else {
  141 + time = Date.parse(new Date($(el).find('input.date').val())) / 1000;
  142 + }
  143 + offsetTime = time - nowTime;
  144 + startTick(el, offsetTime);
  145 + }
  146 + /**
  147 + * [开始倒计时]
  148 + */
  149 + function startTick(el, offsetTime) {
  150 + var hour = parseInt(offsetTime / (60 * 60), 10);
  151 + var minute = parseInt(offsetTime % (60 * 60) / 60, 10);
  152 + var second = offsetTime % 60;
  153 + $(el).find('.tick.hour').text(hour < 0 ? '00': (hour<10?('0'+hour):hour));
  154 + $(el).find('.tick.minute').text(minute < 0 ? '00': (minute<10?('0'+minute):minute));
  155 + $(el).find('.tick.second').text(second < 0 ? '00': (second<10?('0'+second):second));
  156 + if (offsetTime <= 0) { //结束倒计时刷新状态
  157 + refreshList(el);
  158 + } else {
  159 + setTimeout(function() {
  160 + startTick(el, --offsetTime);
  161 + }, 1000);
  162 + }
  163 + }
  164 +
  165 + $(window).resize(function() {
  166 + initNav();
  167 + })
  168 +
  169 + initNav();
  170 +
  171 + var focus = $('.nav-ul>li.focus');
  172 + if (focus.length && (focus.hasClass('now') || focus.hasClass('wait'))) {
  173 + initTick($('.nav-ul>li.focus'));
  174 + }
27 175
28 }()) 176 }())
1 .seckill { 1 .seckill {
2 .seckill-times{ 2 .seckill-times{
3 - height: 3.4rem;  
4 - border-top: 1px solid #e0e0e0;  
5 - border-bottom: 1px solid #e0e0e0; 3 + height: 119px;
  4 + border-top: 1px solid #e1e1e1;
  5 + border-bottom: 1px solid #e1e1e1;
6 .time-item { 6 .time-item {
7 float: left; 7 float: left;
8 } 8 }
@@ -10,7 +10,6 @@ @@ -10,7 +10,6 @@
10 box-sizing: border-box; 10 box-sizing: border-box;
11 -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 11 -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
12 } 12 }
13 -  
14 html, 13 html,
15 body { 14 body {
16 width: 100%; 15 width: 100%;
@@ -18,6 +17,15 @@ body { @@ -18,6 +17,15 @@ body {
18 font-family: helvetica, Arial, "黑体"; 17 font-family: helvetica, Arial, "黑体";
19 line-height: 1.4; 18 line-height: 1.4;
20 } 19 }
  20 +.width750 {
  21 + font-size: 28px;
  22 + .main-wrap {
  23 + max-width: 750px;
  24 + }
  25 + .good-failure {
  26 + background-size: 155px !important;
  27 + }
  28 +}
21 29
22 button, 30 button,
23 input, 31 input,
  1 +.width750 {
  2 + .yoho-footer {
  3 + font-size: 28px;
  4 + }
  5 + .op-row {
  6 + padding: 0 35px;
  7 + height: 140px;
  8 + line-height: 140px;
  9 + .user-name {
  10 + margin-right: 1.17em;
  11 + margin-left: 0.35em;
  12 + max-width: 234px;
  13 + }
  14 + .back-to-top {
  15 + right: 47px;
  16 + }
  17 + .sep-line {
  18 + margin: 0 0.35em;
  19 + }
  20 +
  21 + }
  22 + .copyright {
  23 + height: 140px;
  24 + line-height: 140px;
  25 + }
  26 +}
1 .yoho-footer { 27 .yoho-footer {
2 position: relative; 28 position: relative;
3 width: 100%; 29 width: 100%;
@@ -10,7 +10,36 @@ @@ -10,7 +10,36 @@
10 font-size: 20PX; 10 font-size: 20PX;
11 line-height: 90px; 11 line-height: 90px;
12 } 12 }
13 - 13 +.width750 {
  14 + .yoho-header {
  15 + height: 105px;
  16 + line-height: 105px;
  17 + .nav-back {
  18 + left: 12px;
  19 + width: 105px;
  20 + height: 105px;
  21 + line-height: 105px;
  22 + }
  23 + .nav-home {
  24 + right: 12px;
  25 + width: 105px;
  26 + height: 105px;
  27 + line-height: 105px;
  28 + }
  29 + .nav-btn {
  30 + right: 12px;
  31 + width: 105px;
  32 + height: 105px;
  33 + line-height: 105px;
  34 + }
  35 + .nav-title {
  36 + margin-right: 117px;
  37 + margin-left: 117px;
  38 + font-size: 42px;
  39 + font-weight: normal;
  40 + }
  41 + }
  42 +}
14 .yoho-header { 43 .yoho-header {
15 position: relative; 44 position: relative;
16 z-index: 1; 45 z-index: 1;
@@ -76,6 +105,18 @@ @@ -76,6 +105,18 @@
76 } 105 }
77 } 106 }
78 107
  108 +.width750 {
  109 + .system-update {
  110 + height: 105px;
  111 + line-height: 105px;
  112 + .system-header {
  113 + font-size: 70px;
  114 + }
  115 + span {
  116 + font-size: 94px;
  117 + }
  118 + }
  119 +}
79 .system-update { 120 .system-update {
80 display: none; 121 display: none;
81 overflow: hidden; 122 overflow: hidden;
@@ -106,6 +147,24 @@ @@ -106,6 +147,24 @@
106 } 147 }
107 } 148 }
108 149
  150 +.width750 {
  151 + .homebuttom {
  152 + height: 105px;
  153 + ul {
  154 + padding-top: 14px;
  155 + li {
  156 + i {
  157 + margin-bottom: 9px;
  158 + }
  159 +
  160 + span {
  161 + line-height: 47px;
  162 + font-size: 16px;
  163 + }
  164 + }
  165 + }
  166 + }
  167 +}
109 .homebuttom { 168 .homebuttom {
110 position: relative; 169 position: relative;
111 z-index: 2; 170 z-index: 2;
@@ -14,7 +14,19 @@ @@ -14,7 +14,19 @@
14 opacity: 1; 14 opacity: 1;
15 } 15 }
16 } 16 }
17 - 17 +.width750 {
  18 + .loading {
  19 + margin-top: -23px;
  20 + margin-left: -70px;
  21 + width: 140px;
  22 + height: 47px;
  23 + > div {
  24 + margin: 5px;
  25 + width: 35px;
  26 + height: 35px;
  27 + }
  28 + }
  29 +}
18 .loading-mask { 30 .loading-mask {
19 position: fixed; 31 position: fixed;
20 top: 0; 32 top: 0;
1 -@import "nav";  
  1 +@import "nav";
  2 +@import "product";
  3 +@import "seckill";
1 -.nav-list {  
2 - width: auto;  
3 - ul { 1 +
  2 +.seckill-list {
  3 + .nav-list {
  4 + background-color: #fff;
4 width: auto; 5 width: auto;
5 - overflow: hidden;  
6 - white-space: nowrap;  
7 - display: table;  
8 - li{  
9 - width: 4rem;  
10 - height: 2rem;  
11 - border: solid 1px #ccc;  
12 - display: inline-block; 6 + border-top: solid 1PX #e1e1e1;
  7 + border-bottom: solid 1PX #e1e1e1;
  8 + height: 119px;
  9 + ul {
  10 + width: auto;
  11 + overflow: hidden;
  12 + height: 100%;
  13 + padding-top: 20px;
  14 + li{
  15 + width: 226px;
  16 + height: 79px;
  17 + border-right: solid 1PX #e1e1e1;
  18 + text-align: center;
  19 + float: left;
  20 +
  21 + $status-list: over, now, wait;
  22 + @each $status in $status-list {
  23 + &.$(status) {
  24 + .tip-$(status),
  25 + .info-$(status) {
  26 + display: initial;
  27 + }
  28 + }
  29 + }
  30 + &.last {
  31 + .last-info {
  32 + display: block;
  33 + },
  34 + .last-count-down {
  35 + display: none
  36 + }
  37 + }
  38 + .status,
  39 + .last-info {
  40 + display: none;
  41 + }
  42 +
  43 + p {
  44 + font-size: 22px;
  45 + }
  46 +
  47 + &:last-child {
  48 + border: none;
  49 + }
  50 +
  51 + &.focus {
  52 + width: 300px;
  53 + .selected {
  54 + display: block;
  55 + }
  56 + .normal {
  57 + display: none;
  58 + }
  59 + }
  60 + .selected {
  61 + display: none;
  62 + color: #d0021b;
  63 + height: 79px;
  64 + }
  65 + .normal {
  66 + display: block;
  67 + height: 79px;
  68 + }
  69 + .time {
  70 + font-size: 30px;
  71 + span {
  72 + margin-right: 5px;
  73 + }
  74 + }
  75 + .tick {
  76 + font-size: 20px;
  77 + background-color: #d60117;
  78 + color: #fff;
  79 + margin-left: 10px;
  80 + border-radius: 3PX;
  81 + padding-left: 5px;
  82 + padding-right: 5px;
  83 + }
  84 + }
13 } 85 }
14 } 86 }
15 } 87 }
16 -  
  1 +.seckill-list {
  2 + .product-list {
  3 + background-color: #fff;
  4 + .item {
  5 + padding: 20px 30px;
  6 + display: -webkit-box;
  7 + border-bottom: solid 1PX #e1e1e1;
  8 + &:first-child {
  9 + border-top: solid 1PX #e1e1e1;
  10 + }
  11 +
  12 + .item-img {
  13 + width: 152px;
  14 + margin-right: 30px;
  15 + img {
  16 + width: 100%;
  17 + }
  18 + }
  19 + .item-info {
  20 + -webkit-box-flex: 1;
  21 + position: relative;
  22 + min-height: 202px;
  23 + .item-title {
  24 + font-size: 28px;
  25 + color: #444;
  26 + }
  27 + .item-price {
  28 + margin-top: 15px;
  29 + ins {
  30 + color: #d0021b;
  31 + font-size: 34px;
  32 + text-decoration: none;
  33 + margin-right: 10px;
  34 + }
  35 + del {
  36 + font-size: 20px;
  37 + color: #000;
  38 + color: rgb(176, 176, 176);
  39 + text-decoration: none;
  40 + }
  41 + }
  42 + .item-foot {
  43 + position: absolute;
  44 + left: 0px;
  45 + right: 0px;
  46 + bottom: 0px;
  47 + display: -webkit-box;
  48 + .item-price {
  49 + -webkit-box-flex: 1;
  50 + }
  51 + .item-time {
  52 + -webkit-box-flex: 1;
  53 +
  54 + font-size: 22px;
  55 + padding-top: 28px;
  56 + -webkit-box-align: end;
  57 + i {
  58 + margin-right: 5px;
  59 + color: #b0b0b0;
  60 + }
  61 + span {
  62 + color: #b0b0b0;
  63 + }
  64 + }
  65 + .item-button {
  66 + width: 200px;
  67 + text-align: right;
  68 + .btn {
  69 + width: 155px;
  70 + height: 60px;
  71 + color: #fff;
  72 + background-color: #d0021b;
  73 + border-radius: 3PX;
  74 + border: none;
  75 + font-size: 28px;
  76 +
  77 + &.btn-buy {
  78 + background-color: #d0021b;
  79 + }
  80 + &.btn-over {
  81 + background-color: #b2b2b2;
  82 + }
  83 + &.btn-chance {
  84 + background-color: #fff;
  85 + border: solid 1PX #454545;
  86 + color: #454545;
  87 + }
  88 + }
  89 + .old-price {
  90 + font-size: 20px;
  91 + color: #d0021b;
  92 + line-height: 30px;
  93 + }
  94 + }
  95 + }
  96 + }
  97 + }
  98 + }
  99 +
  100 +}
  1 +.seckill-list {
  2 + background-color: #f0f0f0;
  3 +
  4 + .tips {
  5 + height: 60px;
  6 + line-height: 60px;
  7 + font-size: 24px;
  8 + color: #b0b0b0;
  9 + padding-left: 30px;
  10 + padding-right: 30px;
  11 + }
  12 +}