feat: 修复页面滚动问题
This commit is contained in:
@@ -90,6 +90,7 @@
|
||||
:scroll-into-view="scrollIntoViewId"
|
||||
scroll-with-animation
|
||||
@scroll="handleProductScroll"
|
||||
@touchstart="enableProductScrollSync"
|
||||
>
|
||||
<view class="px-[12px] pb-[24px]">
|
||||
<view v-if="!groups.length" class="pt-[80px] text-center">
|
||||
@@ -142,6 +143,23 @@
|
||||
import { computed, getCurrentInstance, nextTick, onMounted, ref, watch } from 'vue'
|
||||
import TopNavBar from "@/components/TopNavBar/index.vue"
|
||||
|
||||
const createCategoryScrollSelection = () => {
|
||||
let shouldSyncFromScroll = true
|
||||
|
||||
return {
|
||||
select(groupId) {
|
||||
shouldSyncFromScroll = false
|
||||
return groupId
|
||||
},
|
||||
resumeScrollSync() {
|
||||
shouldSyncFromScroll = true
|
||||
},
|
||||
resolve(currentGroupId, scrollGroupId) {
|
||||
return shouldSyncFromScroll ? scrollGroupId : currentGroupId
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
homeData: { type: Object, required: true },
|
||||
})
|
||||
@@ -164,6 +182,7 @@ const scrollIntoViewId = ref('')
|
||||
const leftScrollIntoViewId = computed(() => `ticket-nav-${activeGroupId.value}`)
|
||||
const groupOffsets = ref([])
|
||||
const rightScrollTop = ref(0)
|
||||
const categoryScrollSelection = createCategoryScrollSelection()
|
||||
const instance = getCurrentInstance()
|
||||
const scenicMetaText = computed(() =>
|
||||
[props.homeData.levelText, props.homeData.subtitle].filter(Boolean).join('|')
|
||||
@@ -178,8 +197,13 @@ const isActiveGroup = (groupId) =>
|
||||
const productsForGroup = (group) =>
|
||||
Array.isArray(group.products) ? group.products : []
|
||||
|
||||
const enableProductScrollSync = () => {
|
||||
categoryScrollSelection.resumeScrollSync()
|
||||
scrollIntoViewId.value = ''
|
||||
}
|
||||
|
||||
const selectGroup = (groupId) => {
|
||||
activeGroupId.value = groupId
|
||||
activeGroupId.value = categoryScrollSelection.select(groupId)
|
||||
scrollIntoViewId.value = ''
|
||||
nextTick(() => {
|
||||
scrollIntoViewId.value = `ticket-group-${groupId}`
|
||||
@@ -225,7 +249,12 @@ const handleProductScroll = (event) => {
|
||||
(current, group) => (group.top <= activationLine ? group : current),
|
||||
groupOffsets.value[0]
|
||||
)
|
||||
if (activeGroup?.id) activeGroupId.value = activeGroup.id
|
||||
if (activeGroup?.id) {
|
||||
activeGroupId.value = categoryScrollSelection.resolve(
|
||||
activeGroupId.value,
|
||||
activeGroup.id
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(measureGroupOffsets)
|
||||
|
||||
@@ -63,6 +63,40 @@ test("storefront synchronizes the left category from right-column scrolling", as
|
||||
assert.match(source, /TopNavBar/);
|
||||
});
|
||||
|
||||
test("left category selection wins over programmatic product scrolling", async () => {
|
||||
const source = await readTicketFile("components/TicketHome.vue");
|
||||
const factorySource = source.match(
|
||||
/const createCategoryScrollSelection = \(\) => \{[\s\S]*?^\}\n/m
|
||||
)?.[0];
|
||||
|
||||
assert.match(source, /@touchstart="enableProductScrollSync"/);
|
||||
assert.doesNotMatch(source, /category-scroll-selection\.mjs/);
|
||||
assert.ok(factorySource, "inline category scroll selection factory missing");
|
||||
assert.match(source, /const categoryScrollSelection =\s*createCategoryScrollSelection\(\)/);
|
||||
assert.match(
|
||||
source,
|
||||
/const selectGroup = \(groupId\) => \{\s*activeGroupId\.value = categoryScrollSelection\.select\(groupId\)/
|
||||
);
|
||||
assert.match(
|
||||
source,
|
||||
/const enableProductScrollSync = \(\) => \{\s*categoryScrollSelection\.resumeScrollSync\(\)\s*scrollIntoViewId\.value = ''\s*\}/
|
||||
);
|
||||
assert.match(
|
||||
source,
|
||||
/const handleProductScroll = \(event\) => \{[\s\S]*rightScrollTop\.value = Number[\s\S]*measureGroupOffsets\(\)[\s\S]*activeGroupId\.value = categoryScrollSelection\.resolve\(\s*activeGroupId\.value,\s*activeGroup\.id\s*\)/
|
||||
);
|
||||
|
||||
const createCategoryScrollSelection = Function(
|
||||
`${factorySource}\nreturn createCategoryScrollSelection`
|
||||
)();
|
||||
const selection = createCategoryScrollSelection();
|
||||
const clickedGroupId = selection.select("second");
|
||||
|
||||
assert.equal(selection.resolve(clickedGroupId, "first"), "second");
|
||||
selection.resumeScrollSync();
|
||||
assert.equal(selection.resolve(clickedGroupId, "third"), "third");
|
||||
});
|
||||
|
||||
test("ticket storefront loads API home data without a static adapter", async () => {
|
||||
const source = await readTicketFile("index.vue");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user