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