Authored by 沈志敏

全球购

'use strict';
const headerModel = require('../../../doraemon/models/header');
const model = require('../models/global');
const list = (req, res, next) => {
let brand = req.query.brand;
let sort = req.query.sort;
let title = req.query.title;
if (!brand && !sort) {
return res.redirect('//m.yohobuy.com');
}
let param = {
limit: 12,
order: 's_t_desc',
page: 1,
uid: req.user.uid || 0
};
if (brand) {
param.brand = brand;
} else if (sort) {
param.sort = sort;
}
let arrs = [model.list(param)];
if (brand) {
arrs.push(model.getBrand({
brandId: brand,
uid: req.user.uid || 0,
client_type: 'iphone' // todo
}));
}
Promise.all(arrs).then((result) => {
let t = (result[1] || {}).brand_name || title;
param.title = t;
res.render('global/list', {
module: 'product',
page: 'global-list',
pageHeader: headerModel.setNav({
navTitle: t
}),
list: result[0].list,
filter: result[0].filter,
pageFooter: true,
localCss: true,
appPath: `yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.globalpurchase","params":${JSON.stringify(param)}}`
});
}).catch(next);
};
const search = (req, res, next) => {
let query = req.query;
if (query.type === 'new') {
query.order = 's_t_desc';
} else if (query.type === 'price') {
query.order = query.order === '1' ? 's_p_asc' : 's_p_desc';
}
model.list(query).then((result) => {
res.render('global/search', {
list: result.list,
layout: false
});
}).catch(next);
};
const detail = (req, res, next) => {
let skn = req.params[0];
let params = {
product_skn: skn,
uid: req.user.uid || 0,
client_type: 'iphone' // todo
};
model.detail(params).then((result) => {
let appParams = {
skn: skn
};
let appPath = `yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.globalpurchase","params":${JSON.stringify(appParams)}}`;
res.render('global/detail', {
module: 'product',
page: 'global-detail',
pageHeader: headerModel.setNav({
navTitle: '商品详情'
}),
result: result,
cartUrl: '//m.yohobuy.com/cart/index/index',
pageFooter: true,
localCss: true,
appPath: appPath
});
}).catch(next);
};
const gethtml = (req, res, next) => {
let skn = req.query.skn;
if (!skn) {
return next();
}
let params = {
product_skn: skn,
uid: req.user.uid || 0,
client_type: 'iphone' // todo
};
model.gethtml(params).then((html) => {
res.send(html);
}).catch(next);
};
module.exports = {
list,
search,
detail,
gethtml
};
... ...
'use strict';
const utils = '../../../utils';
const productProcess = require(`${utils}/product-process`);
const globalapi = global.yoho.GlobalAPI;
const $ = require('cheerio');
exports.list = (param) => {
return globalapi.get('product/api/v2/detail/getlist', param).then((result) => {
if (!result || !result.data) {
return {};
}
return {
filter: productProcess.processFilter(result.data.filter || []),
list: result.data.product_list.map((data) => {
return {
product_url: `//m.yohobuy.com/product/global/${data.product_skn}.html`,
product_img: data.default_images,
price: data.formart_final_price,
product_name: data.product_name,
country_name: data.country_name,
is_stock: data.is_stock,
is_limited: data.is_limited,
is_plane: data.is_plane
};
})
};
});
};
exports.getBrand = (param) => {
return globalapi.get('editor/api/v1/brand/get', param).then((data) => {
return data.data || {};
});
};
exports.detail = (param) => {
return globalapi.get('product/api/v2/detail/get', param).then((result) => {
if (!result || !result.data) {
return {};
}
result = result.data;
let goods = result.goods_list || [];
if (goods.length === 1) {
result.bannerTop = {
img: (goods[0].images_list[0] || {}).image_url
};
} else {
result.bannerTop = {
list: goods.map((g) => {
return {
img: (g.images_list[0] || {}).image_url
};
})
};
}
result.show_final_price = result.formart_final_price;
if (result.formart_final_price !== result.formart_orign_price) {
result.show_orign_price = result.formart_orign_price;
}
result.show_sales_price = result.format_sales_price;
if (result.format_market_price !== result.format_sales_price) {
result.show_market_price = result.format_market_price;
}
if (result.brand_info && result.brand_info.brand_id) {
result.brand_info.brand_url = `//m.yohobuy.com/product/global/list?brand=${result.brand_info.brand_id}`;
}
if (result.illustrate_contents && result.illustrate_contents.length) {
result.illustrate = {
title1: (result.illustrate_contents[0] || {}).title,
content1: (result.illustrate_contents[0] || {}).content,
title2: (result.illustrate_contents[1] || {}).title,
content2: (result.illustrate_contents[1] || {}).content
};
}
return result;
});
};
exports.gethtml = (param) => {
return globalapi.get('product/api/v1/detail/gethtml', param, {
cache: true
}).then((result) => {
result = result || '';
result = $.load(result);
result = result('.good-detail-page');
// 修改为你优选url
result.find('.recommend-for-you a.swiper-slide').each((index, el)=> {
el = $(el);
let href = el.attr('href');
if (href) {
let o = (href.split('?')[1] || '').replace('openby:yohobuy=', '');
o = JSON.parse(o);
el.attr('href', `//m.yohobuy.com/product/global/${o.params.skn}.html`);
}
});
return (result.html() || '').replace(/<img src=/g, '<img class="lazy" src="data:image/gif;' +
'base64,R0lGODlhAQABAJEAAAAAAP///93d3f///yH5BAEAAAMALAAAAAABAAEAAAICVAEAOw=="' +
' data-original=').replace(/<img border="0" src=/g, '<img border="0" class="lazy" ' +
'src="data:image/gif;base64,' +
'R0lGODlhAQABAJEAAAAAAP///93d3f///yH5BAEAAAMALAAAAAABAAEAAAICVAEAOw=="' +
' data-original=');
});
};
... ...
... ... @@ -53,6 +53,9 @@ const newShop = require(`${cRoot}/new-shop`);
// 套装
const bundle = require(`${cRoot}/bundle`);
// 全球购
const globalPro = require(`${cRoot}/global`);
// routers
// /pro_136349_455445/HEARTSOFARMianMaShuJiaoXiuXianKuPS1684.html
... ... @@ -201,4 +204,9 @@ router.get('/detail/limitHelp', newDetail.limitHelp);
router.get('/index/allBrand', newShop.allBrand); // 店铺全部品牌
router.get('/global/list', globalPro.list); // 全球购列表页
router.get('/global/search', globalPro.search); // 全球购列表页搜索数据
router.get(/^\/global\/(\d+)\.html/, globalPro.detail); // 全球购店铺详情页
router.get('/global/gethtml', globalPro.gethtml); // 全球购商品信息
module.exports = router;
... ...
{{# result}}
<div id="global-detail-page" class="global-detail-page yoho-page" data-skn="{{product_skn}}">
<div class="banner-container">
<div class="global-tag">
<div class="global-country">
{{#isEqualOr is_plane 'Y'}}
<span class="global-plane"></span>
{{/isEqualOr}}
<span>{{country_name}}</span>
</div>
{{#isEqualOr is_limited 'Y'}}
<div class="global-limited">
<span>限量</span>
</div>
{{/isEqualOr}}
</div>
{{# bannerTop}}
{{> detail/banner-swiper-arrow}}
{{/ bannerTop}}
</div>
<div class="goods-name"><span class="name">{{product_name}}</span></div>
<div class="price-date">
<div>
<span class="final-price">{{show_final_price}}</span>
{{# show_orign_price}}
<span class="orign-price">{{.}}</span>
{{/ show_orign_price}}
</div>
<div>
<span class="sales-price">当前价:{{show_sales_price}}</span>
{{# show_market_price}}
<span class="market-price">原价:{{.}}</span>
{{/ show_market_price}}
</div>
</div>
<div class="country">
<span class="country-name">{{country_name}}</span>
<span class="product-source">{{product_source}}</span>
</div>
{{# illustrate}}
<div class="illustrate">
<div class="illustrate-title">
<div class="title checked"><i class="iconfont checked"></i>{{title1}}</div>
<div class="title notice"><i class="iconfont notice"></i>{{title2}}</div>
<div class="illustrate-down"><i class="iconfont down"></i></div>
</div>
<div class="illustrate-contents">
<div class="content checked">
<i class="iconfont checked"></i>{{title1}}
<div class="text">{{content1}}</div>
</div>
<div class="content notice">
<i class="iconfont notice"></i>{{title2}}
<div class="text">{{content2}}</div>
</div>
<div class="illustrate-up"><i class="iconfont up"></i></div>
</div>
</div>
{{/ illustrate}}
{{# brand_info}}
<div class="enter-store">
{{#if brand_ico}}
<a class="store-logo" href="{{brand_url}}">
<img class="lazy" src="{{image2 brand_ico w=47 h=47 q=60}}" alt="{{brand_name}}">
</a>
{{/if}}
<a class="store-name" href="{{brand_url}}">{{brand_name}}</a>
<a class="store-link" href="{{brand_url}}">进入店铺<span class="iconfont">&#xe604;</span></a>
</div>
{{/ brand_info}}
<div class="customer-service">
<a href="{{customer_service}}">
<span class="customer-name">全球购购物须知</span>
<span class="customer-link iconfont">&#xe604;</span>
</a>
</div>
<div id="productDesc" class="product-desc"></div>
<div class="cart-bar">
{{#unless @root.wap.common.removeCartCount}}
<input type="hidden" id="remove-cart-count" value="1">
{{/unless}}
<a href="{{../cartUrl}}" class="num-incart iconfont"><span class="num-tag hide"></span>&#xe62c;</a>
<a href="javascript:;" class="addto-cart">下载APP购买</a>
</div>
</div>
{{/ result}}
... ...
<div class="global-list-page yoho-page">
<div class="filter-tab">
<ul id="list-nav" class="list-nav clearfix">
<li class="active new buriedpoint" data-bp-id="shop_listnav_new_1">
<a href="javascript:void(0);">
<span class="nav-txt">最新</span>
</a>
</li>
<li class="price buriedpoint" data-bp-id="shop_listnav_price_1">
<a href="javascript:void(0);">
<span class="nav-txt">价格</span>
<span class="icon">
<i class="iconfont up cur">&#xe615;</i>
<i class="iconfont down">&#xe616;</i>
</span>
</a>
</li>
<li class="filter buriedpoint" data-bp-id="shop_listnav_filter_1">
<a href="javascript:void(0);">
<span class="nav-txt">筛选</span>
<span class="iconfont cur">&#xe613;</span>
</a>
</li>
</ul>
</div>
<div id="global-container" class="global-container">
<div class="new-goods container clearfix">
<div class="global-list clearfix">
{{# list}}
<div class="good-info">
<div class="global-tag-container clearfix">
<div class="global-country">
{{#isEqualOr is_plane 'Y'}}
<span class="global-plane"></span>
{{/isEqualOr}}
<span>{{country_name}}</span>
</div>
{{#isEqualOr is_limited 'Y'}}
<div class="global-limited">
<span>限量</span>
</div>
{{/isEqualOr}}
</div>
<div class="good-detail-img">
{{#isEqualOr is_stock 'N'}}
<div class="global-saleout">
<div class="bg"></div>
<span class="text">售罄</span>
</div>
{{/isEqualOr}}
<a class="good-thumb" href="{{product_url}}">
<img src="{{image2 product_img w=235 h=314 q=60}}">
</a>
</div>
<div class="good-detail-text">
<div class="name">
<a href="{{product_url}}">{{product_name}}</a>
</div>
<div class="price">
<span class="sale-price">{{price}}</span>
</div>
</div>
</div>
{{/ list}}
</div>
</div>
<div class="price-goods container clearfix hide"></div>
{{> common/filter}}
</div>
</div>
\ No newline at end of file
... ...
{{# list}}
<div class="good-info">
<div class="global-tag-container clearfix">
<div class="global-country">
{{#isEqualOr is_plane 'Y'}}
<span class="global-plane"></span>
{{/isEqualOr}}
<span>{{country_name}}</span>
</div>
{{#isEqualOr is_limited 'Y'}}
<div class="global-limited">
<span>限量</span>
</div>
{{/isEqualOr}}
</div>
<div class="good-detail-img">
{{#isEqualOr is_stock 'N'}}
<div class="global-saleout">
<div class="bg"></div>
<span class="text">售罄</span>
</div>
{{/isEqualOr}}
<a class="good-thumb" href="{{product_url}}">
<img src="{{image2 product_img w=235 h=314 q=60}}">
</a>
</div>
<div class="good-detail-text">
<div class="name">
<a href="{{product_url}}">{{product_name}}</a>
</div>
<div class="price">
<span class="sale-price">{{price}}</span>
</div>
</div>
</div>
{{/ list}}
\ No newline at end of file
... ...
... ... @@ -11,12 +11,19 @@ const isProduction = process.env.NODE_ENV === 'production';
const isTest = process.env.NODE_ENV === 'test';
const domains = {
api: 'http://dev-api.yohops.com:9999/',
service: 'http://dev-service.yohops.com:9999/',
liveApi: 'http://testapi.live.yohops.com:9999/',
singleApi: 'http://api-test3.yohops.com:9999/',
// api: 'http://api-test3.yohops.com:9999/',
// service: 'http://service-test3.yohops.com:9999/',
api: 'http://api.yoho.cn/',
service: 'http://service.yoho.cn/',
global: 'http://api-global.yohobuy.com',
// liveApi: 'http://api.live.yoho.cn/',
// singleApi: 'http://single.yoho.cn/',
imSocket: 'ws://socket.yohobuy.com:10240',
imCs: 'http://im.yohobuy.com/api'
};
... ... @@ -109,6 +116,7 @@ if (isProduction) {
domains: {
api: 'http://api.yoho.yohoops.org/',
service: 'http://service.yoho.yohoops.org/',
global: 'http://api-global.yohobuy.com',
liveApi: 'http://api.live.yoho.cn/',
singleApi: 'http://single.yoho.cn/',
imSocket: 'wss://imsocket.yohobuy.com:443',
... ... @@ -157,6 +165,7 @@ if (isProduction) {
domains: {
api: process.env.TEST_API || 'http://api-test1.yohops.com:9999/',
service: process.env.TEST_SERVICE || 'http://service-test1.yohops.com:9999/',
global: process.env.TEST_GLOBAL || 'http://global-test-soa.yohops.com:9999',
liveApi: process.env.TEST_LIVE || 'http://testapi.live.yohops.com:9999/',
singleApi: process.env.TEST_SINGLE || 'http://api-test1.yohops.com:9999/',
imSocket: process.env.TEST_IM_SOCKET || 'ws://socket.yohobuy.com:10240',
... ...
'use strict';
import {
Controller
} from 'yoho-mvc';
import {
DetailView
} from './view';
import {
globalSearch as search
} from '../models';
class ListController extends Controller {
constructor() {
super();
this.detail = new DetailView();
this.created();
}
created() {
let skn = this.detail.getSkn();
if (!skn) {
return;
}
setTimeout(() => {
search('//m.yohobuy.com/product/global/gethtml', {
skn: skn
}).then((html) => {
this.detail.setDetailHtml(html);
});
if (this.detail.getCart()) {
search('/cart/index/count').then((data) => {
let count;
if (data.code === 200) {
count = data.data.cart_goods_count || 0;
if (count === 0) {
return false;
}
if (count > 99) {
count = '99+';
}
this.detail.setCartCount(count);
}
});
}
}, 500);
}
}
module.exports = ListController;
... ...
require('product/global/detail.page.css');
const DetailController = require('./controller');
require('common/footer');
new DetailController();
... ...
import {
View
} from 'yoho-mvc';
let Swiper = require('yoho-swiper');
let lazyLoad = require('yoho-jquery-lazyload');
let dialog = require('plugin/dialog');
export class DetailView extends View {
constructor() {
super('#global-detail-page');
this.on('click', '.addto-cart', this.showDownLoadDialog.bind(this));
this.on('click', '.illustrate-title', this.illustrateDown.bind(this));
this.on('click', '.illustrate-contents', this.illustrateUp.bind(this));
this.illustrateTitle = $('.illustrate-title');
this.illustrateContents = $('.illustrate-contents');
this.illustrateContents.hide().addClass('down-animate');
setTimeout(() => {
new Swiper('.banner-swiper', {
preloadImages: false,
lazyLoading: true,
lazyLoadingInPrevNext: true,
lazyLoadingOnTransitionStart: true,
paginationClickable: true,
pagination: '.banner-top .pagination-inner',
nextButton: '.my-swiper-button-next',
prevButton: '.my-swiper-button-prev',
spaceBetween: 3
});
}, 500);
let $cartBar = $('.cart-bar');
let timer = setInterval(function() {
if ($cartBar) {
window.reMarginFooter('.cart-bar');
clearInterval(timer);
} else {
$cartBar = $('.cart-bar');
}
}, 500);
}
showDownLoadDialog() {
dialog.showDialog({
dialogText: '进入有货APP',
hasFooter: {
rightBtnText: '打开Yoho!Buy有货APP'
}
}, function() {
let appUrl = $('#main-wrap').data('apppath');
let ifr = document.createElement('iframe');
ifr.src = appUrl;
ifr.style.display = 'none';
document.body.appendChild(ifr);
window.location.href = appUrl;
let time = Date.now();
window.setTimeout(function() {
document.body.removeChild(ifr);
if (Date.now() - time < 3200) {
window.location.href = 'http://a.app.qq.com/o/simple.jsp?pkgname=com.yoho';
}
}, 3000);
}, null, true);
$('.dialog-wrapper').off('touchstart').on('touchstart', function(para) {
para.stopPropagation();
if ($(para.target).hasClass('dialog-wrapper')) {
dialog.hideDialog();
}
});
}
illustrateDown() {
this.illustrateTitle.hide();
this.illustrateContents.show();
setTimeout(()=>{
this.illustrateContents.removeClass('down-animate');
}, 10);
}
illustrateUp() {
this.illustrateContents.addClass('down-animate');
setTimeout(()=>{
this.illustrateContents.hide();
this.illustrateTitle.show();
}, 500);
}
getCart() {
return $('#remove-cart-count').length;
}
setCartCount(count) {
$('.cart-bar').find('.num-tag').html(count).removeClass('hide');
}
setDetailHtml(htmldata) {
let $productDesc = $('#productDesc');
$productDesc.append(htmldata);
window.rePosFooter && window.rePosFooter();
lazyLoad($productDesc.find('img.lazy'));
this.productDescStyle();
}
productDescStyle() {
new Swiper('#swiper-recommend', {
slidesPerView: 'auto',
grabCursor: true,
slideElement: 'a',
lazyLoading: true,
watchSlidesVisibility: true
});
let $service = $('.service-cont'),
serviceH = $service.height(),
serviceLi = $service.find('li'),
showH = parseInt(serviceLi.eq(0).height()) + parseInt(serviceLi.eq(1).height()) - parseInt(serviceLi.eq(1).find('.service-answer').height()) / 2; // eslint-disable-line
$service.css({
height: showH,
overflow: 'hidden'
});
this.operation = {
showH,
serviceH
};
this.on('click', '.service-operation', this.serviceOperation.bind(this));
}
serviceOperation(e) {
function serviceState(opt) {
opt.dom.html(opt.txt + '<i class="service-icon shrink-btn-' + opt.btnClass + '"></i>');
$('.service-cont').animate({
height: opt.height
}, 0, function() {
$(this).css({
overflow: opt.of
});
});
}
let $this = $(e.currentTarget);
let curState = $this.find('i').hasClass('shrink-btn-up');
if (curState) {
serviceState({
dom: $this,
txt: '展开',
btnClass: 'down',
height: this.operation.showH,
of: 'hidden'
});
} else {
serviceState({
dom: $this,
txt: '收起',
btnClass: 'up',
height: this.operation.serviceH,
of: 'visible'
});
}
}
getSkn() {
return this.$base.data('skn');
}
}
... ...
'use strict';
import {
Controller
} from 'yoho-mvc';
import {
NavView,
ContentView
} from './view';
import {
globalSearch as search
} from '../models';
let filter = require('plugin/filter');
let noResultHbs = require('product/search/no-result-new.hbs');
class ListController extends Controller {
constructor() {
super();
this.navView = new NavView();
this.content = new ContentView();
this.page = 1;
this.searching = false;
this.nav = this.navView.getDefaultNav();
this.nav.reload = false;
this.query = $.extend(this.queryString(), {
type: 'new',
order: this.nav.order
});
this.navView.on('nav-change', this.doNavChange.bind(this));
this.content.on('search', this.doSearch.bind(this));
this.created();
}
queryString() {
let vars = {},
hash,
i;
let hashes = window.location.search.slice(1).split('&');
for (i = 0; i < hashes.length; i++) {
hash = hashes[i].split('=');
vars[hash[0]] = hash[1];
}
return vars;
}
doNavChange(e, nav, navType) {
this.content.doContentChange(e, navType);
this.nav = nav;
if (nav.reload) {
this.nav.page = 0;
} else if (nav.end) {
return;
}
this.query = $.extend(this.query, {
type: navType,
order: nav.order
});
if (this.nav.page === 0) {
this.search();
}
}
doSearch() {
if (!this.nav.end) {
this.search();
}
}
search(opt) {
if (this.searching) {
return;
}
let ext = {};
if (opt) {
switch (opt.type) {
case 'ageLevel':
ext = {
age_level: opt.id
};
break;
default:
ext[opt.type] = opt.id;
break;
}
this.query = $.extend({}, this.query, ext);
this.nav.reload = true;
this.nav.page = 0;
['sort', 'color', 'price'].forEach((k) => {
if (this.query[k] === 0) {
delete this.query[k];
}
});
}
let page = this.nav.page + 1;
let params = $.extend({}, this.query, {
page: page
});
this.searching = true;
search('//m.yohobuy.com/product/global/search', params).then(data => {
this.nav.page = page;
if (!data) {
this.nav.end = true;
if (this.nav.reload) {
this.content.setList(noResultHbs(), {
reload: true
});
}
} else {
if (this.nav.reload) {
this.content.setList(data, {
reload: true
});
} else {
this.content.setList(data, {});
}
}
}).catch(() => {}).finally(() => {
this.nav.reload = false;
this.searching = false;
});
}
created() {
this.navView.setFilter(filter);
filter.initFilter({
fCbFn: this.search.bind(this),
hCbFn: () => {
this.navView.preActive();
}
});
}
}
module.exports = ListController;
... ...
require('product/global/list.page.css');
const ListController = require('./controller');
require('common/footer');
new ListController();
... ...
import {
View
} from 'yoho-mvc';
/**
* 排序 nav view
*/
class NavView extends View {
constructor() {
super('#list-nav');
// 初始化变量
this.navType = '';
this.navInfo = {
new: {
order: 0,
reload: true,
page: 1,
end: false
},
price: {
order: 1,
reload: true,
page: 0,
end: false
}
};
this.$pre = this.$base.find('.active');
// 事件委托
this.on('touchend touchcancel', 'li', this.onTabClick.bind(this));
}
/**
* nav tab click 事件处理
* @param {*} e
*/
onTabClick(e) {
let $this = $(e.currentTarget);
let $active;
if ($this.hasClass('filter')) {
// 筛选面板切换状态
if ($this.hasClass('active')) {
this.filter.hideFilter();
} else {
this.$pre = $this.siblings('.active');
this.filter.showFilter();
}
this.$pre.toggleClass('active');
$this.toggleClass('active');
return;
} else {
if ($this.hasClass('new')) {
this.navType = 'new';
} else if ($this.hasClass('price')) {
this.navType = 'price';
}
}
let nav = this.navInfo[this.navType];
if ($this.hasClass('active')) {
// 最新无排序切换
if ($this.hasClass('new')) {
return;
}
if ($this.hasClass('price')) {
// 价格切换排序状态
$this.find('.icon > .iconfont').toggleClass('cur');
this.$pre = $this; // 更新pre为当前项
nav.reload = true; // 重置reload,HTML会被替换为逆序的HTML
nav.order = nav.order === 0 ? 1 : 0; // 切换排序
}
} else {
$active = $this.siblings('.active');
this.$pre = $this; // $pre为除筛选导航的其他导航项,若当前active的为筛选,则把$pre置为当前点击项
if ($active.hasClass('filter')) {
// 若之前active项为筛选,则隐藏筛选面板
this.filter.hideFilter();
}
$active.removeClass('active');
$this.addClass('active');
}
this.emit('nav-change', nav, this.navType);
}
// 获取默认排序
getDefaultNav() {
return this.navInfo.new;
}
// 设置前一个tab为选中状态
preActive() {
this.$pre.addClass('active');
this.$pre.siblings('.filter').removeClass('active');
}
setFilter(filter) {
this.filter = filter;
}
}
/**
* 商品列表 view
*/
class ContentView extends View {
constructor() {
super('#global-container');
this.$ngc = this.$base.children('.new-goods');
this.$pgc = this.$base.children('.price-goods');
this.$current = this.$ngc;
this.winH = $(window).height();
// srcoll to load more
$(window).scroll(() => {
window.requestAnimationFrame(this.scrollHandler.bind(this));
});
}
/**
* 滚动事件处理
*/
scrollHandler() {
// 当scroll到1/2$goodsContainer高度后继续请求下一页数据
if ($(window).scrollTop() + this.winH >
$(document).height() - 0.5 * this.$current.height()) {
this.emit('search');
}
}
/**
* 商品列表切换
* @param {*} e
* @param {*} navType
*/
doContentChange(e, navType) {
// 切换container显示
this.$base.children('.container:not(.hide)').addClass('hide');
switch (navType) {
case 'new':
this.$ngc.removeClass('hide');
this.$current = this.$ngc;
break;
case 'price':
this.$pgc.removeClass('hide');
this.$current = this.$pgc;
break;
default:
break;
}
}
setList(data, opts) {
if (opts.reload) {
this.$current.html(data);
} else {
this.$current.append(data);
}
}
}
export {
NavView,
ContentView
};
... ...
'use strict';
import {
http
} from 'yoho-mvc';
function globalSearch(url, data) {
return http({
type: 'GET',
url: location.protocol + url,
data: data,
xhrFields: {
withCredentials: true
}
});
}
export {
globalSearch
};
... ...
'use strict';
const $ = require('yoho-jquery');
class View {
constructor(ele) {
this.$base = $(ele);
}
on(event, target, fn) {
if (typeof target === 'function') {
fn = target;
target = null;
}
if (this.$base) {
if (target) {
this.$base.on(event, target, fn);
} else {
this.$base.on(event, fn);
}
}
}
emit(event, ...data) {
this.$base.trigger(event, data);
}
}
class Controller {
constructor() {
}
}
function http(options) {
let ajax = $.ajax(options);
ajax.then = ajax.done.bind(ajax);
ajax.catch = ajax.fail.bind(ajax);
ajax.finally = ajax.always.bind(ajax);
return ajax;
}
export {
View, Controller, http
};
... ...
.global-detail-page {
background: rgb(244, 244, 244);
.global-tag {
position: absolute;
top: 10px;
left: 10px;
z-index: 2;
}
.global-country {
float: left;
background: rgb(70, 46, 61);
color: #fff;
padding: 2px 8px;
font-size: 16px;
span {
float: left;
}
}
.global-plane {
width: 21px;
height: 21px;
background-image: url("/product/airplane.png");
background-repeat: no-repeat;
background-size: cover;
margin-right: 10px;
margin-top: 2px;
}
.global-limited {
float: left;
top: 10px;
border: 1px solid rgb(70, 46, 61);
margin-left: 5px;
padding: 0 5px;
font-size: 16px;
}
.banner-container {
position: relative;
background-color: #fff;
min-height: 660px;
}
.banner-top-single {
overflow: hidden;
margin: 0 auto;
img {
margin-top: 30px;
margin-bottom: 30px;
width: 448px;
}
&.hover {
position: fixed;
width: 100%;
background-color: black;
height: 100%;
top: 0;
left: 0;
right: 0;
border: 0;
z-index: 999;
display: -webkit-flex;
display: -moz-flex;
display: -ms-flex;
display: -o-flex;
display: flex;
-ms-align-items: center;
align-items: center;
img {
margin-top: initial;
margin-bottom: initial;
width: 100%;
}
}
}
.banner-top {
position: relative;
overflow: hidden;
min-height: 660px;
display: flex;
align-items: center;
&.hover {
position: fixed;
width: 100%;
background-color: black;
height: 100%;
top: 0;
left: 0;
right: 0;
border: 0;
z-index: 999;
.banner-swiper {
width: 100%;
height: auto;
margin: 0 !important;
overflow: initial !important;
max-height: initial !important;
ul {
max-height: initial !important;
}
}
.swiper-pagination-bullet-active {
background-color: #fff !important;
}
}
.swiper-pagination {
position: absolute;
bottom: 40px;
z-index: 2;
.pagination-inner {
span {
background-color: #b0b0b0;
}
.swiper-pagination-bullet {
margin-right: 2PX;
}
.swiper-pagination-bullet-active {
background-color: #000;
}
}
}
}
.banner-swiper {
overflow: hidden;
margin: 30px 96px;
width: 448px;
min-height: 600px;
ul {
position: relative;
height: auto;
li {
float: left;
img {
height: auto;
}
}
}
}
.goods-name {
box-sizing: border-box;
padding: 20px 28px;
width: 100%;
background-color: #515150;
color: #fff;
.name {
font-size: 28px;
line-height: 48px;
}
}
.price-date {
height: 112px;
border-bottom: 1px solid #eee;
padding: 15px 30px;
background: #fff;
.final-price {
font-size: 34px;
color: #d0021b;
margin-right: 5px;
}
.orign-price {
text-decoration: line-through;
color: #b0b0b0;
}
.sales-price,
.market-price {
font-size: 24px;
color: #b0b0b0;
}
.market-price {
text-decoration: line-through;
margin-left: 5px;
}
}
.country {
height: 88px;
padding: 30px;
border-bottom: 1px solid #eee;
background: #fff;
.country-name {
float: left;
height: 28px;
background: rgb(70, 46, 61);
color: #fff;
font-size: 18px;
line-height: 28px;
padding: 0 10px;
margin-right: 15px;
}
.product-source {
float: left;
height: 28px;
line-height: 28px;
font-size: 28px;
}
}
.illustrate {
.iconfont {
font-size: 25px;
margin-right: 8px;
}
.iconfont.checked:before {
content: "\E646";
}
.iconfont.notice:before {
content: "\E628";
}
.iconfont.down:before {
content: "\E616";
}
.iconfont.up:before {
content: "\E615";
}
}
.illustrate-title {
height: 88px;
padding: 30px;
font-size: 25px;
line-height: 25px;
border-bottom: 1px solid #eee;
background: #fff;
.title {
float: left;
margin-right: 20px;
}
.notice {
color: #b0b0b0;
}
}
.illustrate-contents {
height: 215px;
border-bottom: 1px solid #eee;
background: #fff;
position: relative;
padding: 30px;
font-size: 22px;
line-height: 22px;
transition: height 500ms;
overflow: hidden;
&.down-animate {
height: 50px;
}
.notice {
margin-top: 20px;
color: #b0b0b0;
}
.text {
margin-top: 10px;
margin-left: 25px;
color: #b0b0b0;
font-size: 18px;
}
}
.illustrate-down {
float: right;
margin-right: 0;
font-size: 30px;
font-weight: 700;
color: #b0b0b0;
}
.illustrate-up {
position: absolute;
top: 30px;
right: 30px;
font-size: 30px;
font-weight: 700;
color: #b0b0b0;
}
.enter-store {
position: relative;
margin-top: 30px;
overflow: hidden;
padding: 0 180px 0 114px;
background-color: #fff;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 84px;
border-top: 1px solid #eee;
border-bottom: 1px solid #eee;
.store-logo {
position: absolute;
top: 1px;
left: 0;
margin-left: 30px;
width: 68px;
height: 84px;
text-align: center;
font-size: 0;
img {
display: inline-block;
width: auto;
height: 68px;
vertical-align: middle;
}
}
.store-name {
color: #444;
font-size: 34px;
}
.store-link {
position: absolute;
top: 1px;
right: 0;
padding-right: 30px;
color: #b0b0b0;
text-align: right;
span {
font-size: inherit;
}
}
}
.customer-service {
margin-top: 30px;
height: 110px;
line-height: 110px;
background-color: #fff;
padding-left: 30px;
font-size: 28px;
border-top: 1px solid #eee;
border-bottom: 1px solid #eee;
a {
display: block;
height: 100%;
width: 100%;
overflow: hidden;
}
.customer-name {
float: left;
color: #444;
}
.customer-link {
float: right;
padding-right: 30px;
color: #b0b0b0;
}
}
.cart-bar {
position: fixed;
bottom: 0;
z-index: 2;
height: 120px;
width: 100%;
border-top: 1px solid #e0e0e0;
background-color: #fff;
text-align: center;
overflow: hidden;
.num-incart {
position: absolute;
color: #444;
font-size: 47px;
top: 50%;
left: 28px;
transform: translateY(-50%);
}
.addto-cart {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 260px;
height: 80px;
background-color: #eb0313;
color: #fff;
text-align: center;
font-size: 32px;
line-height: 80px;
}
.num-tag {
position: absolute;
top: 0;
right: -15px;
display: block;
width: 30px;
height: 30px;
border-radius: 50%;
background: #eb0313;
color: #fff;
text-align: center;
font-size: 20px;
line-height: 30px;
&.hide {
display: none;
}
}
}
}
... ...
.global-detail-page .product-desc {
margin-top: 30px;
font-size: 12px;
.info {
margin: 20px 0;
padding: 0 10px 20px;
background: #fff;
border-top: 1px solid #e0e0e0;
border-bottom: 1px solid #e0e0e0;
}
.service-info {
padding-bottom: 0;
}
.brand-intro {
font-size: 21px;
}
.info:first-child {
margin-top: 0;
}
.info h2 {
text-align: left;
font-size: 28px;
font-weight: normal;
margin: 0;
height: 93px;
line-height: 93px;
border-bottom: 1px solid #f0f0f0;
margin-bottom: 10px;
}
.info h2 span {
font-size: 12px;
text-transform: uppercase;
color: #c0c0c0;
}
.good-sure {
padding-top: 5px;
margin-bottom: -20px;
border-bottom: none;
}
.description {
border-top: none;
}
.description table {
background: #fff;
width: 100%;
border-collapse: collapse;
border-spacing: 0;
}
.description td {
text-align: left;
padding: 5px 10px;
border: 1px solid #fff;
background: #eee;
font-size: 12px;
}
.details {
overflow-x: hidden;
}
.details p {
width: 100%;
line-height: 45px;
font-size: 25px;
}
.details img,
.size img,
.good-sure img,
.brand-intro img {
width: 100%;
}
.table-wrap {
width: 100%;
overflow-x: auto;
}
.size table {
width: 100%;
border-collapse: collapse;
border-spacing: 2;
}
.size th,
.size td {
font-weight: normal;
height: 30px;
background: #eee;
padding-left: 10px;
padding-right: 10px;
border: 1px solid #fff;
min-width: 50px;
text-align: center;
}
.details table {
display: none;
}
.recommend-for-you {
border-bottom: none;
}
.recommend-for-you {
padding: 30px 0;
border-top: 1px solid #e0e0e0;
border-bottom: 1px solid #e0e0e0;
background: #fff;
}
.recommend-for-you .title {
font-size: 32px;
line-height: 88px;
text-align: center;
color: #444;
}
.recommend-for-you .swiper-container {
padding: 30px 0 20px;
width: 100%;
}
.recommend-for-you .swiper-container .swiper-slide {
padding: 0 10px;
float: left;
width: 156px;
}
.recommend-for-you .swiper-container .swiper-slide:first-child {
padding-left: 30px;
}
.recommend-for-you .swiper-container .swiper-slide:last-child {
padding-right: 30px;
}
.recommend-for-you .swiper-container .swiper-slide img {
width: 100%;
height: 208px;
}
.recommend-for-you .sale-name {
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
white-space: nowrap;
margin-top: 20px;
color: gray;
}
.recommend-for-you .price {
position: relative;
margin-top: 8px;
font-size: 24px;
line-height: 1;
}
.recommend-for-you .price .sale-price {
display: block;
color: #d9134f;
margin-right: 8px;
}
.recommend-for-you .price .old-price {
display: block;
color: #b0b0b0;
text-decoration: line-through;
}
.recommend-for-you .price .no-price {
color: #444;
}
.service-cont p {
line-height: 30px;
text-indent: 0;
position: relative;
padding: 0 20px 0 42px;
margin: 20px 0;
}
.service-cont > li {
padding: 10px 0 0;
margin-left: 20px;
border-bottom: 1px solid #e0e0e0;
}
.service-cont > li:last-child {
border-bottom: none;
}
.service-cont .service-prob:before,
.service-cont .service-answer:before {
content: "";
width: 30.8px;
height: 30.8px;
float: left;
margin-right: 20px;
position: absolute;
left: 0;
background-size: contain;
}
.service-cont .service-prob:before {
background-image: url("/product/service-q.png");
background-repeat: no-repeat;
}
.service-cont .service-answer:before {
background-image: url("/product/service-a.png");
background-repeat: no-repeat;
}
.service-cont .service-prob {
font-size: 24px;
color: #444344;
}
.service-cont .service-answer {
font-size: 22px;
color: #b0b0b0;
line-height: 36px;
}
.service-operation {
border-top: 1px solid #e0e0e0;
text-align: center;
height: 80px;
line-height: 80px;
font-size: 24px;
color: #b0b0b0;
}
.service-icon {
display: inline-block;
}
.shrink-btn-down {
background-image: url("/product/service_down.png");
background-repeat: no-repeat;
}
.shrink-btn-up {
background-image: url("/product/service_up.png");
background-repeat: no-repeat;
}
.shrink-btn-up,
.shrink-btn-down {
width: 16px;
height: 9px;
vertical-align: middle;
margin-left: 10px;
cursor: pointer;
}
}
... ...
.global-list-page {
.list-nav {
border-top: 2px solid #fff;
border-bottom: 1px solid #e6e6e6;
> li {
float: left;
width: 33%;
height: 33PX;
line-height: 33PX;
text-align: center;
font-size: 14PX;
}
a {
display: block;
box-sizing: border-box;
width: 100%;
height: 100%;
color: #999;
}
.nav-txt {
display: inline-block;
height: 100%;
box-sizing: border-box;
}
.active > a {
color: #000;
.iconfont {
color: #999;
&.cur {
color: #000;
}
}
}
.new .iconfont {
transform: scale(0.8);
font-weight: bold;
font-size: 12PX;
}
.filter .iconfont {
font-size: 12PX;
transition: transform 0.1 ease-in;
}
.filter.active .iconfont {
transform: rotate(-180deg);
}
.icon {
position: relative;
i {
position: absolute;
transform: scale(0.8);
font-weight: bold;
}
.up {
top: -11PX;
}
.down {
top: -4PX;
}
}
}
.global-container {
position: relative;
min-height: auto !important;
padding-left: 15px;
padding-top: 20px;
.global-country {
float: left;
background: rgb(70, 46, 61);
color: #fff;
padding: 2px 8px;
font-size: 16px;
span {
float: left;
}
}
.global-limited {
float: left;
border: 1px solid rgb(70, 46, 61);
margin-left: 2px;
padding: 0 5px;
font-size: 16px;
}
.global-saleout {
width: 50px;
height: 50px;
position: absolute;
top: 0;
right: 5px;
.text {
width: 100%;
text-align: center;
font-size: 16px;
line-height: 24px;
position: absolute;
color: #fff;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.bg {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background: #999;
border-radius: 30%;
transform: rotate(45deg);
}
}
.global-plane {
width: 21px;
height: 21px;
background-image: resolve("product/airplane.png");
background-repeat: no-repeat;
background-size: cover;
margin-right: 10px;
margin-top: 2px;
}
.sale-price {
color: #000;
}
}
.no-result-new {
text-align: center;
padding-top: 90px;
padding-bottom: 110px;
p {
color: #ccc;
margin-bottom: 25px;
font-size: 26px;
&:first-child {
color: #444;
font-size: 32px;
}
}
}
}
... ...
@import "detail";
@import "global_product";
@import "layout/swiper";
@import "channel/banner-top";
... ...
@import "common/good";
@import "common/filter";
@import "list";
... ...