Authored by 王水玲

sale 首页

@@ -38,37 +38,54 @@ exports.index = (req, res) => { @@ -38,37 +38,54 @@ exports.index = (req, res) => {
38 limit: 10, 38 limit: 10,
39 order: 's_t_desc' 39 order: 's_t_desc'
40 }).then((result) => { 40 }).then((result) => {
41 - console.log(result.data.filter);  
42 - // result = {  
43 - // headerBanner: {  
44 - // list: [  
45 - // {  
46 - // url: '',  
47 - // src: 'http://img11.static.yhbimg.com/yhb-img01/2016/04/18/06/01abda0859d64f9af63a434ca281d213c5.jpg?imageView2/2/w/640/h/240'  
48 - // },  
49 - // {  
50 - // url: '',  
51 - // src: 'http://img12.static.yhbimg.com/yhb-img01/2016/04/18/05/0239e814b8121913aa67b9ad509bd4e310.jpg?imageView2/2/w/640/h/240'  
52 - // }  
53 - // ]  
54 - // },  
55 - // smallPic: {  
56 - // data: [  
57 - // {  
58 - // url: '',  
59 - // src: 'http://img11.static.yhbimg.com/yhb-img01/2016/05/12/15/011684760312d139ac2429c3678951ebd0.jpg?imageView2/2/w/640/h/403'  
60 - // },  
61 - // {  
62 - // url: '',  
63 - // src: 'http://img11.static.yhbimg.com/yhb-img01/2016/05/12/15/011684760312d139ac2429c3678951ebd0.jpg?imageView2/2/w/640/h/403'  
64 - // },  
65 - // {  
66 - // url: '',  
67 - // src: 'http://img11.static.yhbimg.com/yhb-img01/2016/05/12/15/011684760312d139ac2429c3678951ebd0.jpg?imageView2/2/w/275/h/160'  
68 - // }  
69 - // ]  
70 - // }  
71 - // }; 41 + result = {
  42 + headerBanner: {
  43 + list: [
  44 + {
  45 + url: '',
  46 + src: 'http://img11.static.yhbimg.com/yhb-img01/2016/04/18/06/01abda0859d64f9af63a434ca281d213c5.jpg?imageView2/2/w/640/h/240'
  47 + },
  48 + {
  49 + url: '',
  50 + src: 'http://img12.static.yhbimg.com/yhb-img01/2016/04/18/05/0239e814b8121913aa67b9ad509bd4e310.jpg?imageView2/2/w/640/h/240'
  51 + }
  52 + ]
  53 + },
  54 + smallPic: {
  55 + data: [
  56 + {
  57 + url: '',
  58 + src: 'http://img12.static.yhbimg.com/yhb-img01/2016/04/18/05/0239e814b8121913aa67b9ad509bd4e310.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80'
  59 + },
  60 + {
  61 + url: '',
  62 + src: 'http://img11.static.yhbimg.com/yhb-img01/2016/05/12/15/011684760312d139ac2429c3678951ebd0.jpg?imageView2/2/w/640/h/403'
  63 + },
  64 + {
  65 + url: '',
  66 + src: 'http://img11.static.yhbimg.com/yhb-img01/2016/05/12/15/011684760312d139ac2429c3678951ebd0.jpg?imageView2/2/w/275/h/160'
  67 + }
  68 + ]
  69 + },
  70 + title: {
  71 + title: '最新降价'
  72 + },
  73 + goods: {
  74 + url: 'http://m.yohobuy.com/product/pro_320421_412063/SYSTAGYuanLingWeiYiSYSA601HC09.html',
  75 + thumb: 'http://img10.static.yhbimg.com/goodsimg/2015/12/07/09/01ced0e2ed6a4f2a6d95be70cd0a6c5a56.jpg?imageView/2/w/235/h/314',
  76 + name: 'NEFF ONE OF US RAGLAN L/S 男款森林风连帽卫衣',
  77 + salePrice: '759.00',
  78 + price: '799.00',
  79 + tags: {
  80 + isNew: true,
  81 + isAdvance: false,
  82 + isDiscount: false,
  83 + isYohoood: false,
  84 + isLimited: false
  85 + },
  86 + isSoonSoldOut: true
  87 + }
  88 + };
72 res.render('sale', Object.assign(renderData, result)); 89 res.render('sale', Object.assign(renderData, result));
73 }).catch((err) => { 90 }).catch((err) => {
74 saleLogger(err, res); 91 saleLogger(err, res);
@@ -6,4 +6,54 @@ @@ -6,4 +6,54 @@
6 {{# smallPic}} 6 {{# smallPic}}
7 {{> product/thumb-row}} 7 {{> product/thumb-row}}
8 {{/ smallPic}} 8 {{/ smallPic}}
  9 +
  10 + {{> common/floor-header}}
  11 + <ul id="list-nav" class="list-nav clearfix">
  12 + <li class="new active">
  13 + <a href="javascript:void(0);">
  14 + <span class="span-test">最新</span>
  15 + <span class="iconfont cur">&#xe616;</span>
  16 + </a>
  17 + </li>
  18 + <li class="price">
  19 + <a href="javascript:void(0);">
  20 + <span class="span-test">价格</span>
  21 + <span class="icon">
  22 + <i class="iconfont up cur">&#xe615;</i>
  23 + <i class="iconfont down">&#xe616;</i>
  24 + </span>
  25 + </a>
  26 + </li>
  27 + <li class="discount">
  28 + <a href="javascript:void(0);">
  29 + <span class="span-test">折扣</span>
  30 + <span class="icon">
  31 + <i class="iconfont up cur">&#xe615;</i>
  32 + <i class="iconfont down">&#xe616;</i>
  33 + </span>
  34 + </a>
  35 + </li>
  36 + <li class="filter">
  37 + <a href="javascript:void(0);">
  38 + <span class="span-test">筛选</span>
  39 + <span class="iconfont cur">&#xe613;</span>
  40 + </a>
  41 + </li>
  42 + </ul>
  43 +
  44 + <div id="goods-container" class="goods-container">
  45 + <div class="new-goods container clearfix">
  46 + {{# goods}}
  47 + {{> common/good}}
  48 + {{/ goods}}
  49 + </div>
  50 + <div class="price-goods container hide clearfix"></div>
  51 + <div class="discount-goods container hide clearfix"></div>
  52 +
  53 + {{> common/filter}}
  54 + </div>
  55 +
  56 + {{> common/query-param}}
  57 +
  58 + {{> common/suspend-cart}}
9 </div> 59 </div>
1 <div id="thumb-row"> 1 <div id="thumb-row">
2 {{# data}} 2 {{# data}}
3 <a href="{{url}}"> 3 <a href="{{url}}">
4 - <div class="thumb-row-box" style="background-image:url({{image src 275 160}})"></div> 4 + <img class="thumb-row-box lazy" data-original="{{image src 275 130}}">
5 </a> 5 </a>
6 {{/ data}} 6 {{/ data}}
7 </div> 7 </div>
1 /** 1 /**
2 - * sale 2 + * 商品列表页
3 * @author: wsl<shuiling.wang@yoho.cn> 3 * @author: wsl<shuiling.wang@yoho.cn>
4 * @date: 2016/5/17 4 * @date: 2016/5/17
5 */ 5 */
  6 +
6 var $ = require('yoho-jquery'), 7 var $ = require('yoho-jquery'),
  8 + Swiper = require('yoho-swiper'),
  9 + ellipsis = require('yoho-mlellipsis'),
7 lazyLoad = require('yoho-jquery-lazyload'), 10 lazyLoad = require('yoho-jquery-lazyload'),
8 - Swiper = require('yoho-swiper'); 11 + tip = require('../plugin/tip'),
  12 + filter = require('../plugin/filter'),
  13 + loading = require('../plugin/loading');
  14 +
  15 +var $goodsContainer = $('#goods-container'),
  16 + $goodsChildren = $goodsContainer.children(),
  17 + $ngc = $($goodsChildren.get(0)),
  18 + $pgc = $($goodsChildren.get(1)),
  19 + $dgc = $($goodsChildren.get(2));
  20 +
  21 +var winH = $(window).height(),
  22 + noResult = '<p class="no-result">未找到相关搜索结果</p>';
  23 +
  24 +// 默认筛选条件
  25 +var defaultOpt = require('./query-param');
  26 +
  27 +var $listNav = $('#list-nav'),
  28 +
  29 + // 导航数据信息
  30 + navInfo = {
  31 + newest: {
  32 + order: 1,
  33 + reload: true,
  34 + page: 0,
  35 + end: false
  36 + },
  37 + price: {
  38 + order: 1,
  39 + reload: true,
  40 + page: 0,
  41 + end: false
  42 + },
  43 + discount: {
  44 + order: 1,
  45 + reload: true,
  46 + page: 0,
  47 + end: false
  48 + }
  49 + },
  50 + $pre = $listNav.find('.active'), // 纪录进入筛选前的active项,初始为选中项
  51 + searching;
  52 +
  53 +require('./suspend-cart'); // 悬浮购物车
  54 +
  55 +ellipsis.init();
9 56
10 lazyLoad($('img.lazy')); 57 lazyLoad($('img.lazy'));
11 58
@@ -20,3 +67,325 @@ if ($('.swiper-container .swiper-slide').length > 1) { @@ -20,3 +67,325 @@ if ($('.swiper-container .swiper-slide').length > 1) {
20 pagination: '.banner-top .pagination-inner' 67 pagination: '.banner-top .pagination-inner'
21 }); 68 });
22 } 69 }
  70 +
  71 +/**
  72 + * 筛选注册的回调,筛选子项点击后逻辑
  73 + * 需要执行search的场景:1.点选筛选项;2.relaod为true时切换导航;3.下拉加载
  74 + * @param opt {type, id}
  75 + */
  76 +function search(opt) {
  77 + var setting = {},
  78 + ext,
  79 + att,
  80 + nav, navType,
  81 + page;
  82 +
  83 + if (searching) {
  84 + return;
  85 + }
  86 +
  87 + if (opt) {
  88 +
  89 + // 筛选项变更则重置reload为true
  90 + for (att in navInfo) {
  91 + if (navInfo.hasOwnProperty(att)) {
  92 + navInfo[att].reload = true;
  93 + }
  94 + }
  95 +
  96 + // 处理active状态
  97 + $listNav.children('.active').removeClass('active');
  98 + $pre.addClass('active');
  99 +
  100 + switch (opt.type) {
  101 + case 'gender':
  102 + ext = {
  103 + gender: opt.id
  104 + };
  105 + break;
  106 + case 'brand':
  107 + ext = {
  108 + brand: opt.id
  109 + };
  110 + break;
  111 + case 'sort':
  112 + ext = {
  113 + sort: opt.id
  114 + };
  115 + break;
  116 + case 'color':
  117 + ext = {
  118 + color: opt.id
  119 + };
  120 + break;
  121 + case 'size':
  122 + ext = {
  123 + size: opt.id
  124 + };
  125 + break;
  126 + case 'price':
  127 + ext = {
  128 + price: opt.id
  129 + };
  130 + break;
  131 + case 'discount':
  132 + ext = {
  133 + discount: opt.id
  134 + };
  135 + break;
  136 + default:
  137 + break;
  138 + }
  139 +
  140 + $.extend(defaultOpt, ext); // 扩展筛选项
  141 + }
  142 +
  143 +
  144 + // 导航类别
  145 + if ($pre.hasClass('new')) {
  146 + navType = 'newest';
  147 + } else if ($pre.hasClass('price')) {
  148 + navType = 'price';
  149 + } else if ($pre.hasClass('discount')) {
  150 + navType = 'discount';
  151 + }
  152 +
  153 + nav = navInfo[navType];
  154 +
  155 + page = nav.page + 1;
  156 + if (nav.reload) {
  157 + page = 1;
  158 + } else if (nav.end) {
  159 +
  160 + // 不需要重新加载并且数据请求结束
  161 + return;
  162 + }
  163 +
  164 + $.extend(setting, defaultOpt, {
  165 + type: navType,
  166 + order: nav.order,
  167 + page: page
  168 + });
  169 +
  170 + searching = true;
  171 + loading.showLoadingMask();
  172 +
  173 + $.ajax({
  174 + type: 'GET',
  175 + url: '/product/newsale/selectNewSale',
  176 + data: setting,
  177 + success: function(data) {
  178 + var $container,
  179 + num;
  180 +
  181 + switch (navType) {
  182 + case 'newest':
  183 + $container = $ngc;
  184 + break;
  185 + case 'price':
  186 + $container = $pgc;
  187 + break;
  188 + case 'discount':
  189 + $container = $dgc;
  190 + break;
  191 + default:
  192 + break;
  193 + }
  194 +
  195 + if (data === ' ') {
  196 + nav.end = true;
  197 +
  198 + if (nav.reload) {
  199 + $container.html(noResult);
  200 + }
  201 + } else {
  202 + if (nav.reload) {
  203 + $container.html(data);
  204 + lazyLoad($container.find('.lazy'));
  205 + } else {
  206 + num = $container.find('.good-info').length;
  207 + $container.append(data);
  208 +
  209 + // lazy good-infos who append in
  210 + lazyLoad($container.find('.good-info:gt(' + (num - 1) + ') .lazy'));
  211 + }
  212 + }
  213 +
  214 + nav.reload = false;
  215 + nav.page = page;
  216 +
  217 + searching = false;
  218 + loading.hideLoadingMask();
  219 +
  220 + window.rePosFooter();
  221 +
  222 + $('.good-detail-text .name').each(function() {
  223 + var $this = $(this),
  224 + $title = $this.find('a');
  225 +
  226 + $title[0].mlellipsis(2);
  227 + });
  228 + },
  229 + error: function() {
  230 + tip.show('网络断开连接了~');
  231 + searching = false;
  232 + loading.hideLoadingMask();
  233 + }
  234 + });
  235 +
  236 +}
  237 +
  238 +$.ajax({
  239 + type: 'GET',
  240 + url: '/product/newsale/filter',
  241 + data: defaultOpt,
  242 + success: function(data) {
  243 + $goodsContainer.append(data);
  244 +
  245 + // 初始化filter&注册filter回调
  246 + filter.initFilter({
  247 + fCbFn: search,
  248 + hCbFn: function() {
  249 +
  250 + // 切换active状态到$pre上
  251 + $pre.addClass('active');
  252 + $pre.siblings('.filter').removeClass('active');
  253 + },
  254 + missStatus: true
  255 + });
  256 + }
  257 +});
  258 +lazyLoad($('.lazy'));
  259 +
  260 +// 导航栏点击逻辑说明:
  261 +// 1.点击非active项时切换active状态
  262 +// 2.价格和折扣active状态时继续点击切换排序
  263 +// 3.筛选无active时点击展开筛选面板
  264 +// 4.筛选有active时点击隐藏筛选面板并恢复点击筛选前active项的active状态
  265 +// 5.当前active为筛选并且点击其他项时,隐藏筛选面板
  266 +$listNav.bind('contextmenu', function() {
  267 + return false;
  268 +});
  269 +
  270 +$listNav.on('touchend touchcancel', function(e) {
  271 + var $this = $(e.target).closest('li'),
  272 + nav,
  273 + navType,
  274 + $active;
  275 +
  276 + e.preventDefault();
  277 +
  278 + if (typeof $this === 'undefined' || $this.length === 0) {
  279 + return;
  280 + }
  281 +
  282 + if ($this.hasClass('filter')) {
  283 +
  284 + // 筛选面板切换状态
  285 + if ($this.hasClass('active')) {
  286 + filter.hideFilter();
  287 +
  288 + // 点击筛选钱的active项回复active
  289 + $pre.addClass('active');
  290 + $this.removeClass('active');
  291 + } else {
  292 + $pre = $this.siblings('.active');
  293 +
  294 + $pre.removeClass('active');
  295 + $this.addClass('active');
  296 +
  297 + filter.showFilter();
  298 + }
  299 + } else {
  300 +
  301 + if ($this.hasClass('new')) {
  302 + navType = 'newest';
  303 + } else if ($this.hasClass('price')) {
  304 + navType = 'price';
  305 + } else if ($this.hasClass('discount')) {
  306 + navType = 'discount';
  307 + }
  308 +
  309 + nav = navInfo[navType];
  310 +
  311 + if ($this.hasClass('active')) {
  312 +
  313 + // 最新无排序切换
  314 + if ($this.hasClass('new')) {
  315 + return;
  316 + }
  317 +
  318 + if ($this.hasClass('price') || $this.hasClass('discount')) {
  319 +
  320 + // 价格/折扣切换排序状态
  321 + $this.find('.icon > .iconfont').toggleClass('cur');
  322 + $pre = $this; // 更新pre为当前项
  323 + nav.reload = true; // 重置reload,HTML会被替换为逆序的HTML
  324 + nav.order = nav.order === 0 ? 1 : 0; // 切换排序
  325 + }
  326 + } else {
  327 + $active = $this.siblings('.active');
  328 +
  329 + $pre = $this; // $pre为除筛选导航的其他导航项,若当前active的为筛选,则把$pre置为当前点击项
  330 +
  331 + if ($active.hasClass('filter')) {
  332 +
  333 + // 若之前active项为筛选,则隐藏筛选面板
  334 + filter.hideFilter();
  335 + } else {
  336 +
  337 + // 切换container显示
  338 + $goodsContainer.children('.container:not(.hide)').addClass('hide');
  339 +
  340 + switch (navType) {
  341 + case 'newest':
  342 + $ngc.removeClass('hide');
  343 + break;
  344 +
  345 + case 'price':
  346 + $pgc.removeClass('hide');
  347 + break;
  348 +
  349 + case 'discount':
  350 + $dgc.removeClass('hide');
  351 + break;
  352 + default:
  353 + break;
  354 + }
  355 + }
  356 +
  357 + $active.removeClass('active');
  358 + $this.addClass('active');
  359 + }
  360 +
  361 + if (nav.reload) {
  362 + search();
  363 + }
  364 + }
  365 + e.stopPropagation();
  366 +});
  367 +
  368 +function scrollHandler() {
  369 +
  370 + // 当scroll到1/4$goodsContainer高度后继续请求下一页数据
  371 + if ($(window).scrollTop() + winH >
  372 + $(document).height() - 0.25 * $goodsContainer.height() - 50) {
  373 + if (typeof($pre) !== 'undefined') {
  374 + search();
  375 + }
  376 + }
  377 +}
  378 +
  379 +// srcoll to load more
  380 +$(window).scroll(function() {
  381 + window.requestAnimationFrame(scrollHandler);
  382 +});
  383 +
  384 +// 初始请求最新第一页数据
  385 +search();
  386 +
  387 +$listNav.on('touchstart', 'li', function() {
  388 + $(this).addClass('bytouch');
  389 +}).on('touchend touchcancel', function() {
  390 + $listNav.find('li').removeClass('bytouch');
  391 +});
@@ -12,4 +12,8 @@ @@ -12,4 +12,8 @@
12 @import "product/recommend-for-you"; 12 @import "product/recommend-for-you";
13 @import "product/sale"; 13 @import "product/sale";
14 @import "product/special"; 14 @import "product/special";
  15 +@import "product/discount";
  16 +@import "product/good";
  17 +@import "product/filter";
  18 +@import "product/suspend-cart";
15 @import "cart/chose-panel"; 19 @import "cart/chose-panel";
@@ -20,6 +20,8 @@ @@ -20,6 +20,8 @@
20 height: 90px; 20 height: 90px;
21 line-height: 90px; 21 line-height: 90px;
22 z-index: 1; 22 z-index: 1;
  23 + max-width: 640px;
  24 + margin: 0 auto;
23 25
24 &.boys { 26 &.boys {
25 background-image: linear-gradient(#323232, #414141); 27 background-image: linear-gradient(#323232, #414141);
  1 +.discount-page {
  2 + background-color: #fff;
  3 +
  4 + .swiper-container {
  5 + width: 100%;
  6 + height: 310px;
  7 +
  8 + img {
  9 + height: 100%;
  10 + width: 100%;
  11 + }
  12 +
  13 + .swiper-pagination {
  14 + bottom: 0;
  15 + left: 0;
  16 + width: 100%;
  17 + }
  18 +
  19 + .swiper-pagination-bullet-active {
  20 + background: #fff;
  21 + }
  22 + }
  23 +
  24 + .banner-top-single {
  25 + width: 100%;
  26 + height: 200px;
  27 +
  28 + img {
  29 + display: block;
  30 + height: 100%;
  31 + width: 100%;
  32 + }
  33 + }
  34 +
  35 + .list-nav {
  36 + border-top: 1px solid #e6e6e6;
  37 + border-bottom: 1px solid #e6e6e6;
  38 +
  39 + > li {
  40 + float: left;
  41 + width: 25%;
  42 + height: 66px;
  43 + line-height: 66px;
  44 + text-align: center;
  45 + font-size: 28px;
  46 + }
  47 +
  48 + .bytouch {
  49 + background: #eee;
  50 + }
  51 +
  52 + a {
  53 + display: block;
  54 + box-sizing: border-box;
  55 + width: 100%;
  56 + height: 100%;
  57 + color: #999;
  58 + }
  59 +
  60 + .active > a {
  61 + color: #000;
  62 +
  63 + .span-test {
  64 + width: auto;
  65 + height: 100%;
  66 + display: inline-block;
  67 + box-sizing: border-box;
  68 + }
  69 +
  70 + .iconfont {
  71 + color: #999;
  72 +
  73 + &.cur {
  74 + color: #000;
  75 + }
  76 + }
  77 + }
  78 +
  79 + .new .iconfont {
  80 + transform: scale(0.8);
  81 + font-weight: bold;
  82 + }
  83 +
  84 + .filter .iconfont {
  85 + font-size: 24px;
  86 + transition: transform 0.1 ease-in;
  87 + }
  88 +
  89 + .filter.active .iconfont {
  90 + transform: rotate(-180deg);
  91 + }
  92 +
  93 + .icon {
  94 + position: relative;
  95 +
  96 + i {
  97 + position: absolute;
  98 + transform: scale(0.8);
  99 + font-weight: bold;
  100 + }
  101 +
  102 + .up {
  103 + top: -22px;
  104 + }
  105 +
  106 + .down {
  107 + top: -8px;
  108 + }
  109 + }
  110 + }
  111 +
  112 + .no-result {
  113 + text-align: center;
  114 + vertical-align: middle;
  115 + color: #ccc;
  116 + font-size: 1.2em;
  117 + margin-top: 320px;
  118 + }
  119 +
  120 + .goods-container {
  121 + position: relative;
  122 + min-height: 880px;
  123 + padding-left: 15px;
  124 + padding-top: 8px;
  125 + }
  126 +
  127 +}
1 .sale-page { 1 .sale-page {
  2 + margin-left: auto;
  3 + margin-right: auto;
  4 + width: 100%;
  5 + max-width: 640px;
  6 + overflow: hidden;
2 7
3 #thumb-row { 8 #thumb-row {
4 text-align: left; 9 text-align: left;
  10 + background: #fff;
  11 + height: auto;
  12 + overflow: hidden;
  13 + padding-left: 30px;
  14 +
  15 + a {
  16 + float: left;
  17 + width: 275px;
  18 + height: 130px;
  19 + margin-bottom: 30px;
  20 + margin-right: 30px;
  21 + }
5 22
6 .thumb-row-box { 23 .thumb-row-box {
7 border-radius: 20px; 24 border-radius: 20px;
  25 + width: 100%;
  26 + height: 100%;
  27 + margin: 0 auto;
8 } 28 }
9 } 29 }
10 } 30 }
  1 +.suspend-cart {
  2 + position: fixed;
  3 + width: 88px;
  4 + height: 88px;
  5 + line-height: 88px;
  6 + border-radius: 50%;
  7 + background: rgba(0, 0, 0, 0.3);
  8 + text-align: center;
  9 + right: 30px;
  10 + bottom: 140px;
  11 + z-index: 10;
  12 +
  13 + a {
  14 + display: block;
  15 + width: 100%;
  16 + height: 100%;
  17 + }
  18 +
  19 + .iconfont {
  20 + color: #fff;
  21 + font-size: 36px;
  22 + }
  23 +
  24 + .cart-count {
  25 + position: absolute;
  26 + top: -24px;
  27 + right: -20px;
  28 + width: 72px;
  29 + height: 72px;
  30 + font-size: 40px;
  31 + line-height: 72px;
  32 + color: #fff;
  33 + background: #f03d35;
  34 + text-align: center;
  35 + border-radius: 50%;
  36 + transform: scale(0.5);
  37 + }
  38 +}