Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
飞
飞鹤小程序
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
FH
飞鹤小程序
Commits
9214ed3a
Commit
9214ed3a
authored
Jun 19, 2025
by
张九刚
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 在首页和Home组件中添加滚动事件处理和曝光检测功能,优化用户体验
parent
25005662
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
190 additions
and
25 deletions
+190
-25
index.vue
pages/index/index.vue
+10
-3
exposure.js
utils/exposure.js
+86
-0
Home.vue
views/Home.vue
+94
-22
No files found.
pages/index/index.vue
View file @
9214ed3a
<
template
>
<view
class=
"container"
>
<Home
v-if=
"globalStore.curTabIndex == 0
"
/>
<Home
ref=
"homeRef"
v-if=
"globalStore.curTabIndex == 0"
:scroll-top=
"scrollTop
"
/>
<Brand
v-if=
"globalStore.curTabIndex == 1"
/>
<Integral
v-if=
"globalStore.curTabIndex == 2"
/>
<My
v-if=
"globalStore.curTabIndex == 3"
/>
...
...
@@ -10,7 +10,7 @@
<
script
setup
>
import
{
ref
,
getCurrentInstance
}
from
"vue"
;
import
{
onLoad
,
onShareAppMessage
,
onShareTimeline
}
from
"@dcloudio/uni-app"
;
import
{
onLoad
,
onShareAppMessage
,
onShareTimeline
,
onPageScroll
}
from
"@dcloudio/uni-app"
;
import
TabBar
from
"@/components/TabBar.vue"
;
import
Home
from
"@/views/Home.vue"
;
import
Brand
from
"@/views/Brand.vue"
;
...
...
@@ -21,7 +21,8 @@ import { useGlobalStore } from "@/stores/global.js";
const
globalStore
=
useGlobalStore
();
const
{
proxy
}
=
getCurrentInstance
();
const
$baseUrl
=
proxy
.
$baseUrl
;
const
homeRef
=
ref
(
null
);
const
scrollTop
=
ref
(
0
);
const
shareOptions
=
{
0
:
{
title
:
"8000万中国妈妈信赖的育儿品牌"
,
...
...
@@ -72,6 +73,12 @@ onShareTimeline(() => {
const
pageType
=
globalStore
.
curTabIndex
;
return
shareOptions
[
pageType
]
||
shareOptions
[
0
];
});
onPageScroll
((
e
)
=>
{
if
(
globalStore
.
curTabIndex
===
0
)
{
scrollTop
.
value
=
e
.
scrollTop
;
}
});
</
script
>
<
style
lang=
"scss"
scoped
>
...
...
utils/exposure.js
0 → 100644
View file @
9214ed3a
import
md
from
'../md'
;
class
ExposureTracker
{
constructor
(
component
)
{
this
.
component
=
component
;
this
.
exposureMap
=
new
Map
();
// 记录每个元素的曝光状态
this
.
windowHeight
=
0
;
this
.
init
();
}
init
()
{
// 获取窗口高度
const
systemInfo
=
uni
.
getSystemInfoSync
();
this
.
windowHeight
=
systemInfo
.
windowHeight
;
}
// 添加需要追踪的元素配置
addExposureElement
(
config
)
{
const
{
id
,
logParams
}
=
config
;
if
(
!
this
.
exposureMap
.
has
(
id
))
{
this
.
exposureMap
.
set
(
id
,
{
isExposed
:
false
,
logParams
});
}
}
// 批量添加需要追踪的元素配置
addExposureElements
(
configs
)
{
configs
.
forEach
(
config
=>
this
.
addExposureElement
(
config
));
}
// 检查元素是否在可视区域内
isElementInViewport
(
rect
,
scrollTop
)
{
const
elementTop
=
rect
.
top
;
const
elementBottom
=
rect
.
top
+
rect
.
height
;
const
viewportTop
=
scrollTop
;
const
viewportBottom
=
scrollTop
+
this
.
windowHeight
;
return
(
(
elementBottom
>=
viewportTop
&&
elementBottom
<=
viewportBottom
)
||
(
elementTop
>=
viewportTop
&&
elementTop
<=
viewportBottom
)
||
(
elementTop
<=
viewportTop
&&
elementBottom
>=
viewportBottom
)
);
}
// 检查所有元素的曝光状态
checkExposure
(
scrollTop
)
{
const
query
=
uni
.
createSelectorQuery
().
in
(
this
.
component
);
this
.
exposureMap
.
forEach
((
value
,
id
)
=>
{
if
(
value
.
isExposed
)
return
;
// 如果已经曝光过,则跳过
query
.
select
(
`#
${
id
}
`
)
.
boundingClientRect
(
res
=>
{
if
(
!
res
)
return
;
const
isVisible
=
this
.
isElementInViewport
(
res
,
scrollTop
);
if
(
isVisible
&&
!
value
.
isExposed
)
{
value
.
isExposed
=
true
;
// 触发埋点
md
.
sensorLogTake
(
value
.
logParams
);
}
});
});
query
.
exec
();
}
// 重置某个元素的曝光状态
resetExposure
(
id
)
{
const
element
=
this
.
exposureMap
.
get
(
id
);
if
(
element
)
{
element
.
isExposed
=
false
;
}
}
// 重置所有元素的曝光状态
resetAllExposure
()
{
this
.
exposureMap
.
forEach
(
value
=>
{
value
.
isExposed
=
false
;
});
}
}
export
default
ExposureTracker
;
\ No newline at end of file
views/Home.vue
View file @
9214ed3a
<
template
>
<view
class=
"home-container"
>
<view
class=
"home-container"
@
scroll=
"onPageScroll"
>
<view
class=
"content"
>
<swiper
class=
"swiper banner"
circular
:indicator-dots=
"indicatorDots"
:autoplay=
"autoplay"
<swiper
id=
"firstScreen"
class=
"swiper banner"
circular
:indicator-dots=
"indicatorDots"
:autoplay=
"autoplay"
:interval=
"interval"
:duration=
"duration"
:indicator-color=
"indicatorColor"
:indicator-active-color=
"indicatoractiveColor"
>
<swiper-item
v-for=
"(item, index) in swiperList"
:key=
"item.url"
>
...
...
@@ -67,7 +67,7 @@
</view>
</view>
</view>
<view
class=
"contentbox"
>
<view
class=
"contentbox"
id=
"secondScreen"
>
<image
class=
"contentbg"
:src=
"$baseUrl + 'homepage/contentbg.png'"
alt=
""
/>
<image
class=
"contentitem"
:key=
"index"
:style=
"contentItem._style"
v-for=
"(contentItem, index) in contentImgList"
:src=
"$baseUrl + contentItem.bgUrl"
:data-log=
"
{
...
...
@@ -76,7 +76,7 @@
buttonName: `品牌介绍${index + 1}`
}" @tap="jumpLink(contentItem.link, contentItem.videoUrl, index, $event)">
</image>
</view>
<view
class=
"channelbox"
>
<view
class=
"channelbox"
id=
"thirdScreen"
>
<text
class=
"maintitle"
>
有声频道
</text>
<text
class=
"subtitle"
>
用声音传递爱与智慧,守护宝贝成长的每一步
</text>
<view
class=
"listbox"
>
...
...
@@ -138,7 +138,7 @@
更多星妈会权威专家服务团
<view
class=
"desc1"
>
点击查看 >
</view>
</view>
</view>
<view
class=
"bottomlink"
>
<view
id=
"fourthScreen"
class=
"bottomlink"
>
<image
class=
"bottombg"
:src=
"$baseUrl + 'homepage/bottombg.png'"
></image>
<view
class=
"box"
>
<image
class=
"icon"
v-for=
"(icon, index) in bottomLinkList"
:key=
"index"
:data-log=
"
{
...
...
@@ -179,7 +179,6 @@
<
script
>
import
{
jump
,
JumpType
}
from
'../utils'
;
import
{
homeObj
}
from
'../mock/home'
;
import
{
useHomeStore
}
from
'../stores/home'
;
...
...
@@ -187,9 +186,55 @@ import { fetchHomeJSON } from '../api/home';
import
{
useUserStore
}
from
'../stores/user'
;
import
RegisterLayer
from
"../components/RegisterLayer.vue"
;
import
md
from
'../md'
;
import
ExposureTracker
from
'../utils/exposure'
;
// const homeStore = useHomeStore();
const
userStore
=
useUserStore
();
// 定义需要曝光检测的元素配置
const
EXPOSURE_CONFIGS
=
[
{
id
:
'firstScreen'
,
logParams
:
{
xcxPage
:
'首页-首屏页面浏览'
,
pageName
:
'首页-首屏'
}
},
// 可以添加更多需要曝光检测的元素配置
{
id
:
'secondScreen'
,
logParams
:
{
xcxPage
:
'首页-二屏页面浏览'
,
pageName
:
'首页-二屏'
}
},
{
id
:
'thirdScreen'
,
logParams
:
{
xcxPage
:
'首页-三屏页面浏览'
,
pageName
:
'首页-三屏'
}
},
{
id
:
'fourthScreen'
,
logParams
:
{
xcxPage
:
'首页-四屏页面浏览'
,
pageName
:
'首页-四屏'
}
}
];
export
default
{
beforeDestroy
()
{
if
(
this
.
exposureTracker
)
{
this
.
exposureTracker
.
resetAllExposure
();
}
},
deactivated
()
{
if
(
this
.
exposureTracker
)
{
this
.
exposureTracker
.
resetAllExposure
();
}
},
data
()
{
return
{
popType
:
'bottom'
,
...
...
@@ -219,7 +264,11 @@ export default {
voiceStory
:
{},
suggest
:
{},
videoHeight
:
'56vw'
,
qrNameList
:[
'公众号'
,
'企业微信'
,
'视频号'
,
'小红书'
]
qrNameList
:[
'公众号'
,
'企业微信'
,
'视频号'
,
'小红书'
],
windowHeight
:
0
,
isFirstScreenExposed
:
false
,
scrollTimer
:
null
,
exposureTracker
:
null
,
}
},
components
:
{
...
...
@@ -230,30 +279,49 @@ export default {
return
useHomeStore
();
}
},
mounted
()
{
const
menuButtonInfo
=
wx
.
getMenuButtonBoundingClientRect
();
this
.
statusBarHeight
=
menuButtonInfo
.
top
;
this
.
isClickPhoneAuth
=
false
;
props
:
{
scrollTop
:
{
type
:
Number
,
default
:
0
}
},
watch
:
{
homeStore
:
{
handler
(
newVal
)
{
this
.
showRegisterLayer
=
this
.
isClickPhoneAuth
&&
newVal
.
isLogin
&&
!
newVal
.
babyExistence
;
console
.
log
(
'newVal.homeInfo'
,
newVal
.
homeInfo
);
if
(
newVal
.
homeInfo
!==
null
)
{
this
.
initHomeInfo
();
}
},
deep
:
true
,
immediate
:
true
},
scrollTop
:
{
handler
(
newVal
)
{
this
.
checkExposure
(
newVal
);
}
}
},
mounted
()
{
const
menuButtonInfo
=
wx
.
getMenuButtonBoundingClientRect
();
this
.
statusBarHeight
=
menuButtonInfo
.
top
;
this
.
isClickPhoneAuth
=
false
;
// 获取窗口高度
const
systemInfo
=
uni
.
getSystemInfoSync
();
this
.
windowHeight
=
systemInfo
.
windowHeight
;
// 初始化曝光检测工具
this
.
exposureTracker
=
new
ExposureTracker
(
this
);
this
.
exposureTracker
.
addExposureElements
(
EXPOSURE_CONFIGS
);
// 初始检查曝光
this
.
$nextTick
(()
=>
{
this
.
checkExposure
(
this
.
scrollTop
);
});
},
methods
:
{
async
initHomeInfo
()
{
const
{
data
}
=
await
fetchHomeJSON
();
if
(
data
)
{
this
.
swiperList
=
data
.
swiperList
;
...
...
@@ -269,16 +337,12 @@ export default {
this
.
voiceStory
=
data
.
voiceStory
;
this
.
suggest
=
data
.
suggest
;
if
(
this
.
homeStore
.
isLogin
)
{
this
.
vipCardList
[
0
]
=
data
.
vipConfigList
.
find
(
item
=>
item
.
grade
===
this
.
homeStore
.
homeInfo
?.
grade
);
this
.
vipCardList
[
0
].
level
=
this
.
homeStore
.
homeInfo
?.
gradeName
;
}
else
{
this
.
vipCardList
[
0
]
=
data
.
vipConfigList
[
0
];
}
}
},
changeIndicatorDots
(
e
)
{
this
.
indicatorDots
=
!
this
.
indicatorDots
...
...
@@ -377,7 +441,6 @@ export default {
if
(
_index
===
3
)
{
this
.
qrObj
=
null
;
}
else
{
_index
=
Math
.
max
(
0
,
Math
.
min
(
_index
,
this
.
qrInfoList
.
length
-
1
));
this
.
qrObj
=
this
.
qrInfoList
[
_index
];
...
...
@@ -386,7 +449,6 @@ export default {
this
.
$refs
.
popup
.
open
(
this
.
popType
);
},
closePop
()
{
this
.
$refs
.
popup
.
close
();
},
goSearchHandler
(
e
)
{
...
...
@@ -457,6 +519,16 @@ export default {
const
{
memberId
,
mobile
,
openId
,
unionId
}
=
this
.
homeStore
.
homeInfo
;
const
customerUrl
=
`https://intelcc-user.icsoc.net/?channelKey=45839e0505554f8c8aea3c7b6259b049&init=1&crmld=
${
memberId
}
&mobile=
${
mobile
}
&openId=
${
openId
}
&unionId=
${
unionId
}
`
;
jump
({
type
:
JumpType
.
H5
,
url
:
customerUrl
});
},
checkExposure
(
scrollTop
)
{
if
(
this
.
exposureTracker
)
{
this
.
exposureTracker
.
checkExposure
(
scrollTop
);
}
},
resetExposure
()
{
if
(
this
.
exposureTracker
)
{
this
.
exposureTracker
.
resetAllExposure
();
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment