Authored by 陈峰

Merge branch 'feature/tracking' into 'gray'

Feature/tracking



See merge request !104
... ... @@ -43,7 +43,8 @@ const handleBrandList = origin => {
shopId: subValue.shop_id,
shopName: subValue.brand_name_en || subValue.brand_name_cn || subValue.brand_name,
isRedShop: subValue.is_red_shop,
shopTemplateType: subValue.shop_template_type
shopTemplateType: subValue.shop_template_type,
brandId: subValue.id
});
});
... ... @@ -82,7 +83,8 @@ const handleBrandList = origin => {
shopId: subValue.shop_id,
shopName: subValue.brand_name_en || subValue.brand_name_cn || subValue.brand_name,
isRedShop: subValue.is_red_shop,
shopTemplateType: subValue.shop_template_type
shopTemplateType: subValue.shop_template_type,
brandId: subValue.id
});
});
dest.brandList.push({
... ...
... ... @@ -12,7 +12,8 @@
a.async = 1;
a.src = j;
m.parentNode.insertBefore(a, m);
}(window, document, 'script', (document.location.protocol === 'https:' ? 'https:' : 'http:') + '//cdn.yoho.cn/yas-jssdk/2.4.13/yas.js', '_yas'));
}(window, document, 'script', (document.location.protocol === 'https:' ? 'https:' : 'http:') +
'//cdn.yoho.cn/yas-jssdk/2.4.15/yas.js', '_yas'));
(function() {
function getUid() {
... ... @@ -54,7 +55,7 @@
uid = uid === 0 ? '' : uid;
window._ozuid = uid; // 暴露ozuid
if (window._yas) {
window._yas(1 * new Date(), '2.4.14', 'yohoblk_m', uid, '', '');
window._yas(1 * new Date(), '2.4.15', 'yohoblk_m', uid, '', '');
}
}());
var _hmt = _hmt || [];
... ...
... ... @@ -131,6 +131,35 @@ const miniVersion = function (miniVersion) {
return false;
};
const debounce = function(idle, action) { // 函数去抖动,超过一定时间才会执行,如果周期内触发,重置计时器
let last;
return function() {
let args = arguments;
if (last) {
clearTimeout(last);
}
last = setTimeout(() => {
action.apply(this, args);
}, idle);
};
};
const throttle = function(delay, action) { // 函数节流器,定义函数执行间隔,按频率触发函数
let last = 0;
return function() {
let args = arguments;
let curr = +new Date();
if (curr - last > delay) {
action.apply(this, args);
last = curr;
}
};
};
export default {
getImgHost,
getImgUrl,
... ... @@ -138,5 +167,7 @@ export default {
visibilitychange,
getChannel,
replaceHttp,
miniVersion
miniVersion,
debounce,
throttle
};
... ...
... ... @@ -66,28 +66,33 @@ function BrandHrefBinding(el, binding) {
}
if (!yoho.isYohoBuy) {
el.href = href;
el.href = href + `?brandId=${binding.value.brandId}`;
}
} else {
el.href = `/product/shop/${binding.value}`;
if (binding.value) {
el.href = `/product/shop/${binding.value.brand_domain}?brandId=${binding.value.brand_id}`;
}
}
}
function GoodHrefBinding(el, binding) {
if (binding.value === binding.oldValue) {
return;
}
let {product_id, goods_id, cn_alphabet, product_skn} = binding.value;
let {product_id, goods_id, cn_alphabet, product_skn, from_page_name, from_page_param} = binding.value;
if (!binding.modifiers.collect) {
goods_id = binding.value.goods_list.length ? binding.value.goods_list[0].goods_id : '';
}
let href = `/product/pro_${product_id}_${goods_id}/${cn_alphabet || 'item'}.html`;
const prefix = yoho.isiOS ? 'i' : (yoho.isAndroid ? 'a' : '');
if (yoho.isYohoBuy) {
let goParams = {
action: 'go.productDetail',
params: {
product_skn: product_skn
product_skn: product_skn,
from_page_name: `${prefix}${from_page_name}`,
from_page_param
}
};
... ...
... ... @@ -16,9 +16,6 @@
<style>
.brand-list-box {
width: 100%;
/* padding: 20px 0; */
background: #f6f6f6;
/* border-top: 1px solid #eee; */
... ...
<template>
<div class="exposure-item">
<slot></slot>
</div>
</template>
<script>
import _ from 'lodash';
import yoho from 'yoho';
import util from 'common/util';
export default {
name: 'ExposureItem',
props: {
pageName: {
type: String
},
pageParam: {
type: String,
},
index: {
type: [String, Number]
},
productSkn: {
type: [String, Number]
}
},
data() {
return {
isVisible: false,
appPrefix: yoho.isiOS ? 'i' : (yoho.isAndroid ? 'a' : 'h5')
};
},
methods: {
record(visible, init) {
if (init) {
this.isVisiable = false;
}
// 元素由不可见变为可见则记录,否则不记录
if (!this.isVisiable && visible) {
const param = {
P_NAME: `${this.appPrefix}${this.pageName}` || '', // 页面名称
P_PARAM: this.pageParam || '', // 页面参数
I_INDEX: this.index + 1, // 内部item的序号
PRD_SKN: this.productSkn // 商品SKN (可选)
};
if (param.P_PARAM === '') {
delete param.P_PARAM;
}
this.$parent.addIntoWaiting(param);
}
this.isVisiable = visible;
}
}
};
</script>
<style>
</style>
... ...
<template>
<div class="exposure" ref="exposure">
<slot></slot>
</div>
</template>
<script>
import _ from 'lodash';
import yoho from 'yoho';
import util from 'common/util';
export default {
name: 'Exposure',
props: {
topClassName: {
type: String,
default: 'top-filter'
}
},
data() {
return {
viewArea: {
top: 0,
bottom: 0
},
waiting: []
};
},
watch: {
},
methods: {
checkReport(e, init) {
// 顶部区域可能切换显示和隐藏所以动态获取
const topRect = document.querySelector(`.${this.topClassName}`).getBoundingClientRect();
// 可见区域顶部距离视口的上边的距离
this.viewArea.top = topRect.bottom;
// 可见区域底部距离视口的上边的距离
this.viewArea.bottom = window.screen.height;
let children = _.filter(this.$children, child => {
return child.$options.name === 'ExposureItem'
});
_.each(children, child => {
return child.record(this.isVisible(child.$el), init)
});
},
isVisible($el) {
const rect = $el.getBoundingClientRect();
return ((rect.top > this.viewArea.top && rect.top < this.viewArea.bottom) ||
rect.bottom > this.viewArea.top && rect.bottom < this.viewArea.bottom)
},
addIntoWaiting(param) {
this.waiting.push(param);
}
},
mounted() {
if (yoho.isYohoBuy) {
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
this.checkReport(void 0, true);
}
});
setTimeout(() => {
this.$scrollEl = window;
this.scrollEvent = util.throttle(50, this.checkReport);
if (this.$scrollEl) {
this.$scrollEl.addEventListener('scroll', this.scrollEvent);
}
if (this.$children.length) {
this.checkReport(void 0, true);
}
}, 500);
let reportTimer = setInterval(() => {
if (!this.$children.length) { return clearInterval(reportTimer); }
if (!this.waiting.length) { return }
this.$yas.event('YB_SHOW_EVENT', this.waiting);
this.waiting = [];
}, 3000);
}
}
};
</script>
<style>
</style>
... ...
<template>
<div class="goods-box" v-infinite-scroll="fetch" infinite-scroll-disable="disableFetch" :infinite-scroll-distance="1200">
<ul class="cardlist card-large clearfix">
<li class="card" v-for="(item, index) in data" :key="item.product_skn" @click="clickProduct(item, index)">
<div class="card-pic">
<a v-good-href="item" :class="hrefClass">
<img v-img-src="{src: item.default_images, width: 330, height: 440}" :alt="item.product_name">
</a>
</div>
<div class="card-bd">
<h2 class="card-label">
<a v-good-href="item" class="line-clamp-1" :class="hrefClass">{{item.product_name}}</a>
</h2>
<h2 class="card-label-desc" v-if="item.product_name1">
<a v-good-href="item" class="line-clamp-1" :class="hrefClass">{{item.product_name}}</a>
</h2>
<span class="good-price sale-price">¥{{item.sales_price |
toFixed}}</span>
<span class="good-price" :class="{'old-price': item.market_price}" v-if="item.market_price">¥{{item.market_price | toFixed}}</span>
</div>
</li>
<exposure :top-class-name="topClassName">
<li class="card" v-for="(item, index) in data" :key="item.product_skn"
@click="clickProduct(item, index)">
<exposure-item :page-name="reportPageName" :page-param="reportPageParam" :index="index"
:product-skn="item.product_skn">
<div class="card-pic">
<a v-good-href="item" :class="hrefClass">
<img v-img-src="{src: item.default_images, width: 330, height: 440}" :alt="item.product_name">
</a>
</div>
<div class="card-bd">
<h2 class="card-label">
<a v-good-href="item" class="line-clamp-1" :class="hrefClass">{{item.product_name}}</a>
</h2>
<h2 class="card-label-desc" v-if="item.product_name1">
<a v-good-href="item" class="line-clamp-1" :class="hrefClass">{{item.product_name}}</a>
</h2>
<span class="good-price sale-price">¥{{item.sales_price |
toFixed}}</span>
<span class="good-price" :class="{'old-price': item.market_price}" v-if="item.market_price">¥{{item.market_price | toFixed}}</span>
</div>
</exposure-item>
</li>
</exposure>
</ul>
<p class="cardlist--loading text-center" v-show="state === 1">loading...</p>
<!--<p class="cardlist--end text-center" v-show="state === 0 ">--End--</p>-->
... ... @@ -35,6 +41,8 @@ import Vue from 'vue';
import lazyload from 'vue-lazyload';
import infinitScroll from 'vue-infinite-scroll';
import bus from 'common/vue-bus';
import Exposure from 'component/product/exposure/exposure.vue';
import ExposureItem from 'component/product/exposure/exposure-item.vue';
Vue.use(lazyload, { preLoad: 3 });
Vue.use(infinitScroll);
... ... @@ -49,9 +57,15 @@ export default {
/* 开启滚动加载 */
disableFetch: Boolean,
topClassName: String,
// 数据
data: Array,
state: [Number, Object] // -1: 无数据 0: 全部加载完 1: 正在加载
state: [Number, Object], // -1: 无数据 0: 全部加载完 1: 正在加载
// for yas report
reportPageName: String,
reportPageParam: String,
},
computed: {
// 空列表: data.length === 0
... ... @@ -59,6 +73,12 @@ export default {
return !this.data.length;
}
},
watch: {
reportPageName(v) {
console.log(v)
}
},
mounted() {
const $scrollEl = this.getScrollEventTarget(this.$el);
... ... @@ -105,6 +125,10 @@ export default {
}, delay);
};
}
},
components: {
Exposure,
ExposureItem
}
};
... ...
<template>
<div class="goods">
<product-list :data="productList"></product-list>
<product-list :data="productList" top-class-name="channel-tab"></product-list>
</div>
</template>
... ...
... ... @@ -2,19 +2,19 @@
<div class="fav-type" v-infinite-scroll="loadMore" infinite-scroll-disabled="busy" infinite-scroll-distance="10">
<ul class="fav-brand-list">
<v-touch
v-for="(item, index) in brandData"
v-for="(item, index) in brandData"
tag="li"
:key="item.fav_id"
:id="'li-' + item.fav_id"
:pan-options="{ direction: 'horizontal', threshold: 100}"
:key="item.fav_id"
:id="'li-' + item.fav_id"
:pan-options="{ direction: 'horizontal', threshold: 100}"
@panstart="(evt) => {panstart(item.fav_id, evt)}"
@panmove="(evt) => {panmove(item.fav_id, evt)}"
@panmove="(evt) => {panmove(item.fav_id, evt)}"
@panend="(evt) => {panend(item.fav_id, evt)}">
<div :class="'fav-del-left ' + (editmodel ? 'delshow': '')"
@click="showDelBtn(item.fav_id)">
<span class="fav-del-span"><span class="icon icon-edit-del"></span></span>
</div>
<a v-brand-href="item.brand_domain">
<a v-brand-href="item">
<div class="fav-img-box">
<img v-img-src="{src: item.imgUrl, width: 160, height: 125}" alt=""/>
</div>
... ... @@ -122,6 +122,7 @@
imgUrl: o.brand_ico,
brandName: o.brand_name,
brand_domain: o.brand_domain,
brand_id: o.brand_id,
down: o.status === 0
});
}
... ...
<template>
<div>
<ul class="item-action">
<li><a v-brand-href="brand && brand.brand_domain"><i class="icon icon-store"></i><span
<li><a v-brand-href="brand"><i class="icon icon-store"></i><span
class="action-text">{{brand && brand.brand_name
}}</span></a></li>
<li><i class="icon"
... ...
... ... @@ -2,12 +2,14 @@
<div class="product-list" :class="{'no-header': noheader}">
<header-box :title="sortName" class="list-header"></header-box>
<filter-box :val="order" :filter="filterConfig" v-if="enableOrder"></filter-box>
<product-list :data="productList" :state="listState" class="list-items"></product-list>
<product-list :data="productList" :state="listState" class="list-items"
:report-page-name="pageName" :report-page-param="pageParam"></product-list>
<shopping-bag :cart-count="cartCount" v-if="isApp"></shopping-bag>
</div>
</template>
<script>
import $ from 'jquery';
import _ from 'lodash';
import yoho from 'yoho';
import Vue from 'vue';
import lazyload from 'vue-lazyload';
... ... @@ -50,7 +52,11 @@
inSearching: false, // 请求中
enableOrder: false,
cartCount: 0,
fixIosTop: false
fixIosTop: false,
// for yas report
pageName: 'FP_BLK_Category_h5',
pageParam: locationQuery.sort || ''
};
},
... ... @@ -104,6 +110,13 @@
if (res.data) {
this.page = res.data.page;
this.totalPage = res.data.page_total;
// yas report param injection
_.each(res.data.product_list, item => {
item.from_page_name = this.pageName;
item.from_page_param = this.pageParam;
});
this.productList = this.productList.concat(res.data.product_list);
if (!this.filterConfig) {
... ...
... ... @@ -2,11 +2,13 @@
<div class="product-new" :class="{'no-header': noheader}">
<header-box title="NEW ARRIVAL"></header-box>
<filter-box :val="order" :filter="filterConfig" v-if="enableOrder"></filter-box>
<product-list :data="productList" :state="listState" class="list-items"></product-list>
<product-list :data="productList" :state="listState" class="list-items"
:report-page-name="pageName"></product-list>
<shopping-bag :cart-count="cartCount" v-if="isApp"></shopping-bag>
</div>
</template>
<script>
import _ from 'lodash';
import $ from 'jquery';
import yoho from 'yoho';
import Vue from 'vue';
... ... @@ -49,6 +51,9 @@
enableOrder: false,
order: 's_t_desc',
cartCount: 0,
// for yas report
pageName: 'FP_BLK_New_h5'
};
},
computed: {
... ... @@ -98,6 +103,13 @@
if (res.code === 200) {
this.page = res.data.page;
this.totalPage = res.data.page_total;
// yas report param injection
_.each(res.data.product_list, item => {
item.from_page_name = this.pageName;
item.from_page_param = this.query;
});
this.productList = this.productList.concat(res.data.product_list);
if (!this.filterConfig) {
... ...
<template>
<div>
<filter-box :val="order" :filter="filterConfig" v-if="enableOrder" :search-page="true"></filter-box>
<product-list :data="productList" :state="listState" class="list-items" @click-product="clickProduct"></product-list>
<product-list :data="productList" :state="listState" class="list-items"
@click-product="clickProduct" :report-page-name="pageName"
:report-page-param="query"></product-list>
</div>
</template>
<script>
import Vue from 'vue';
import _ from 'lodash';
import $ from 'jquery';
import lazyload from 'vue-lazyload';
import infinitScroll from 'vue-infinite-scroll';
... ... @@ -37,7 +40,10 @@
inSearching: false,
enableOrder: false,
filterConfig: null,
filter: {}
filter: {},
// for yas report
pageName: 'FP_BLK_Search_h5',
};
},
computed: {
... ... @@ -89,7 +95,6 @@
this.inSearching = true;
return $.get(this.url, Object.assign({
order: this.order, // 排序 信息
query: this.query,
... ... @@ -99,8 +104,14 @@
if (res.data) {
this.page = res.data.page;
this.totalPage = res.data.page_total;
this.productList = this.productList.concat(res.data.product_list);
// yas report param injection
_.each(res.data.product_list, item => {
item.from_page_name = this.pageName;
item.from_page_param = this.query;
});
this.productList = this.productList.concat(res.data.product_list);
if (!this.filterConfig) {
this.filterConfig = res.data.filter;
}
... ...
... ... @@ -2,7 +2,8 @@
<div class="shop-box" :class="{'no-header': noheader}">
<top-bar :share-data="shareData" :show-top-bar="showTopBar"></top-bar>
<div :class='{"shop-goods-top": true}' class="list-items">
<product-list :data="productList" :state="listState"></product-list>
<product-list :report-page-name="pageName" :report-page-param="pageParam" :data="productList"
:state="listState"></product-list>
</div>
<filter-box :val="order" :filter="filterConfig" v-if="enableOrder" ref="filter"></filter-box>
<shopping-bag :cart-count="cartCount" v-if="isApp"></shopping-bag>
... ... @@ -33,6 +34,7 @@
</style>
<script>
import $ from 'jquery';
import _ from 'lodash';
import yoho from 'yoho';
import qs from 'yoho-qs/parse';
import bus from 'common/vue-bus';
... ... @@ -90,7 +92,11 @@
inSearching: false,
enableOrder: false,
order: 's_t_desc',
cartCount: 0
cartCount: 0,
// for yas report
pageName: 'FP_BLK_Brand_h5',
pageParam: locationQuery.brandId || ''
};
},
computed: {
... ... @@ -193,6 +199,13 @@
if (result.code === 200) {
this.page = result.data.page;
this.totalPage = result.data.pageTotal;
// yas report param injection
_.each(result.data.productList, item => {
item.from_page_name = this.pageName;
item.from_page_param = this.pageParam;
});
this.productList = this.productList.concat(result.data.productList);
if (!this.filterConfig) {
this.filterConfig = result.data.filter;
... ...
... ... @@ -32,11 +32,28 @@ export default {
let {product_skn} = product;
let href = `/product/pro_${product_skn}.html`;
const pageNameMap = {
'channel.home': 'FP_BLK_Home_h5',
'channel.channelHome.channelMen': 'FP_BLK_MenHome_h5',
'channel.channelHome.channelWomen': 'FP_BLK_WomenHome_h5'
};
let from_page_name = this.$route.name;
if (this.yoho) {
const prefix = this.yoho.env.isiOS ? 'i' : (this.yoho.env.isAndroid ? 'a' : '');
from_page_name = pageNameMap[this.$route.name] ? `${prefix}${pageNameMap[this.$route.name]}` :
this.$route.name;
}
let from_page_param = Object.keys(this.$route.query).length ? this.$route.query : void 0;
if ((this.$yoho && this.$yoho.isYohoBuy) || this.yoho.env.isYohoBuy) {
let goParams = {
action: 'go.productDetail',
params: {
product_skn: product_skn
product_skn: product_skn,
from_page_name: from_page_name,
from_page_param
}
};
... ...
... ... @@ -14,7 +14,13 @@ export default {
name: 'ResourceBox',
data() {
return {
componentStatus: {}
componentStatus: {},
waiting: [],
pageNameMap: {
'channel.home': 'FP_BLK_Home_h5',
'channel.channelHome.channelMen': 'FP_BLK_MenHome_h5',
'channel.channelHome.channelWomen': 'FP_BLK_WomenHome_h5',
}
};
},
computed: {
... ... @@ -27,7 +33,7 @@ export default {
}
},
['yoho.visible'](visible) {
if (visible && this.$yoho && this.$yoho.isiOS) {
if (visible && this.$yoho) {
this.checkReport(void 0, true);
}
}
... ... @@ -43,6 +49,14 @@ export default {
this.$scrollEl.addEventListener('scroll', this.scrollEvent);
this.checkReport(void 0, true);
}
// 每隔三秒钟上报一次数据
setInterval(() => {
if (this.waiting.length) {
this.report(this.waiting);
this.waiting = [];
}
}, 3000);
},
destroyed() {
if (this.$scrollEl) {
... ... @@ -50,43 +64,115 @@ export default {
}
},
methods: {
report(param) {
const prefix = this.yoho.env.isiOS ? 'i' : (this.yoho.env.isAndroid ? 'a' : '');
_.each(param, item => {
if (this.pageNameMap[item.P_NAME]) {
item.P_NAME = this.pageNameMap[item.P_NAME];
}
item.P_NAME = `${prefix}${item.P_NAME}`;
});
this.$store.dispatch(REPORT_YAS, {
params: {
appop: 'YB_SHOW_EVENT',
param
}
});
},
checkReport(evt, isInit) {
if (isInit) {
this.componentStatus = {};
}
_.each(this.$children, (component, index) => {
const visiable = this.isVisiable(component.$el, this.$scrollEl);
const visible = this.isVisible(component.$el, this.$scrollEl);
if (visiable && (this.componentStatus[index] !== visiable || isInit)) {
this.report(component, index + 1);
if (visible && (this.componentStatus[index] !== visible || isInit)) {
this.record(component, index + 1, isInit);
}
this.componentStatus[index] = visiable;
this.componentStatus[index] = visible;
});
},
report(component, index) {
record(component, index) {
const reportData = _.get(component, '$options.propsData.value');
// 区分不通组件记录以楼层内item为单位、而不是以整个楼层为单位组织数据上报
let param;
if (reportData) {
const param = {
P_NAME: this.$route.name,
F_NAME: reportData.template_name,
F_ID: reportData.template_id,
F_INDEX: index
};
switch (reportData.template_name) {
case 'twoPicture':
param = [];
_.each(reportData.data.list, (item, idx) => {
param.push({
P_NAME: this.$route.name,
F_NAME: reportData.template_name,
F_ID: reportData.template_id,
F_INDEX: index,
I_INDEX: idx + 1,
ACTION_URL: item.url
});
});
break;
case 'focus':
// 由于focus自动轮播的特殊性、上报数据由focus直接调用父组件方法
// 修改waiting数组所以这里不做数据监测
break;
case 'tfGoodsList':
// 楼层内存在多个item, 交给子组件各自检测
let visible = component.checkReqFromParent();
if (visible.length) {
param = [];
_.each(visible, item => {
param.push(Object.assign(item, {
P_NAME: this.$route.name,
F_NAME: reportData.template_name,
F_ID: reportData.template_id,
F_INDEX: index,
}));
});
}
break;
case 'newSingleImage':
param = {
P_NAME: this.$route.name,
F_NAME: reportData.template_name,
F_ID: reportData.template_id,
F_INDEX: index,
I_INDEX: 1,
ACTION_URL: reportData.data.list[0].url
};
break;
default:
break;
}
this.$store.dispatch(REPORT_YAS, {
params: {
appop: 'YB_SHOW_EVENT',
param
}
});
if (param) {
_.isArray(param) ? (this.waiting = this.waiting.concat(param)) : this.waiting.push(param);
}
}
},
isVisiable($el, $parent) {
isVisible($el, $parent) {
const rect = $el.getBoundingClientRect();
const parentRect = $parent.getBoundingClientRect();
return ((parentRect.top >= rect.top && parentRect.top <= (rect.top + rect.height)) ||
((parentRect.top + parentRect.height) >= rect.top && (parentRect.top + parentRect.height) <= (rect.top + rect.height)) ||
(rect.top >= parentRect.top && (rect.top + rect.height) <= (parentRect.top + parentRect.height)));
((parentRect.top + parentRect.height) >= rect.top && (parentRect.top + parentRect.height) <= (rect.top + rect.height)) ||
(rect.top >= parentRect.top && (rect.top + rect.height) <= (parentRect.top + parentRect.height)));
},
checkReqFromChild(index) {
// 重置子组件显示状态方可重新记录
this.componentStatus[index] = false;
this.checkReport();
},
focusComponentDataRecord(index, param) {
if (this.componentStatus[index] && document.visibilityState === 'visible') {
this.waiting.push(param);
}
}
}
};
</script>
\ No newline at end of file
</script>
... ...
... ... @@ -32,8 +32,12 @@
autoplay: true,
pagination: {
el: '.swiper-pagination'
},
on:{
slideChange: this._slideChange,
}
}
},
itemVisibleStatus: {}
};
},
computed: {
... ... @@ -44,6 +48,17 @@
methods: {
swiperSuccess(swiper) {
this.mySwiper = swiper;
// 注册成功后上报首个slide
let param = {
I_INDEX: this.mySwiper.realIndex + 1,
P_NAME: this.$route.name,
F_NAME: this.value.template_name,
F_ID: this.value.template_id,
F_INDEX: this.index + 1,
ACTION_URL: this.value.data[this.mySwiper.realIndex].url
};
this.dataRecord(param);
},
activeLink() {
const img = this.value.data[this.mySwiper.realIndex];
... ... @@ -54,6 +69,30 @@
this.$refs.linkA.click();
});
}
},
_slideChange() {
if (this.mySwiper) {
// fixed: slideChange回调执行时,realIndex为0会前后触发两次
if (this.mySwiper.previousIndex === this.value.data.length + 1) {
return;
}
let param = {
I_INDEX: this.mySwiper.realIndex + 1,
P_NAME: this.$route.name,
F_NAME: this.value.template_name,
F_ID: this.value.template_id,
F_INDEX: this.index + 1,
ACTION_URL: this.value.data[this.mySwiper.realIndex].url
};
this.dataRecord(param);
}
},
dataRecord(param) {
// index 用户父组件判断当前组件是否可见
this.$parent.focusComponentDataRecord(this.index, param)
}
},
components: {Resource}
... ...
<template>
<resource class="no-padding-right product-list-more">
<resource class="no-padding-right product-list-more" ref="resource">
<ul class="resource-tf-goods"
@touchstart="touchStart"
@touchmove="touchMove"
... ... @@ -23,6 +23,7 @@
</template>
<script>
import _ from 'lodash';
import Resource from './resource';
export default {
... ... @@ -34,7 +35,9 @@ export default {
moveX: 0,
disX: 0,
moreSlider: '',
moreMove: ''
moreMove: '',
itemVisibleStatus: {},
checkTimer: ''
};
},
props: {
... ... @@ -103,6 +106,13 @@ export default {
}
},
touchEnd(ev) {
// 手动触发父组件曝光检查, touchEnd事件触发后延迟500ms检查
clearTimeout(this.checkTimer);
this.checkTimer = setTimeout(() => {
this.$parent.checkReqFromChild(this.index);
}, 500);
let wd = this.$refs.goodsList.scrollWidth - this.$refs.goodsList.offsetWidth;
let moreWd = this.$refs.more.offsetWidth;
let scrollLeft = this.$refs.goodsList.scrollLeft;
... ... @@ -136,6 +146,36 @@ export default {
this.$refs.linkA.click();
this.moreSlider = 'transform:translateX(0px)';
this.moreMove = 'transform:translateX(' + this.$refs.more.offsetWidth + 'px)';
},
// 用于检测楼层内部item的曝光状态, 暴露给父组件调用
checkReqFromParent(isInit) {
// 重置item的显示状态重新检测
_.each(this.itemVisibleStatus, (v, k) => {
this.itemVisibleStatus[k] = false
});
let rect;
let isVisible;
let visible = [];
let items = this.$el.querySelectorAll('.product-item');
_.each(items, (item, idx) => {
rect = item.getBoundingClientRect();
isVisible = (rect.left > 0 && rect.left < window.screen.width) ||
((rect.left + rect.width) > 0 && (rect.left + rect.width) < window.screen.width);
if (isVisible && !this.itemVisibleStatus[idx]) {
visible.push({
I_INDEX: idx + 1,
PRD_SKN: this.value.data && this.value.data.list[idx].product_skn
});
}
this.itemVisibleStatus[idx] = isVisible;
});
return visible;
}
},
components: {Resource}
... ...
... ... @@ -18,59 +18,59 @@
(function(w, d, s, j, f) {
var a = d.createElement(s);
var m = d.getElementsByTagName(s)[0];
w.YohoAcquisitionObject = f;
w[f] = function() {
w[f].p = arguments;
};
a.async = 1;
a.src = j;
m.parentNode.insertBefore(a, m);
}(window, document, 'script', (document.location.protocol === 'https:' ? 'https:' : 'http:') + '//cdn.yoho.cn/yas-jssdk/2.4.13/yas.js', '_yas'));
}(window, document, 'script', (document.location.protocol === 'https:' ? 'https:' : 'http:') + '//cdn.yoho.cn/yas-jssdk/2.4.15/yas.js', '_yas'));
(function() {
function getUid() {
var uid,
name = '_UID',
cookies = (document.cookie && document.cookie.split(';')) || [];
for (var i = 0; i < cookies.length; i++) {
if (cookies[i].indexOf(name) > -1) {
uid = decodeURIComponent(cookies[i].replace(name + '=', '').trim());
break;
}
}
if (!uid) return 0;
uid = uid.split('::');
if (!uid || uid.length < 4) {
return 0;
}
return uid[1];
}
function queryString() {
var vars = {},
hash,
i;
var 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;
}
var uid = getUid() || queryString().uid;
uid = uid === 0 ? '' : uid;
window._ozuid = uid; // 暴露ozuid
if (window._yas) {
window._yas(1 * new Date(), '2.4.14', 'yohoblk_m', uid, '', '');
window._yas(1 * new Date(), '2.4.15', 'yohoblk_m', uid, '', '');
}
}());
var _hmt = _hmt || [];
... ... @@ -81,7 +81,7 @@
s.parentNode.insertBefore(hm, s);
})();
</script>
<!--vue-ssr-outlet-->
</body>
</html>
\ No newline at end of file
</html>
... ...
... ... @@ -41,12 +41,23 @@ export default {
}
}
};
window.yohoInterface = window.yohoInterface;
const setInterface = () => {
if (window.frames['iframe']) {
window.frames['iframe'].yohoInterface = window.yohoInterface;
window.frames['iframe'].appBaseLogs = window.appBaseLogs;
}
};
this.$bus.$on('after-view-enter', () => {
this.showIframe = true;
this.$nextTick(() => setInterface());
});
if (this.yoho.env.fs) {
this.showIframe = true;
this.$nextTick(() => setInterface());
}
},
computed: {
... ...