|
|
@ -1,12 +1,17 @@ |
|
|
<template> |
|
|
<template> |
|
|
<ScrollView |
|
|
|
|
|
ref="scroll" |
|
|
|
|
|
:indicators="!indicatorWrapper ? undefined : [{ relationElement: indicatorWrapper, relationElementHandleElementIndex: 0 }]" |
|
|
|
|
|
:class="['brand-scroll', $route.path === '/guide' ? 'guide' : 'brand']" |
|
|
|
|
|
scrollbar |
|
|
|
|
|
|
|
|
<ScrollView ref="scroll" :class="['brand-scroll', $route.path === '/guide' ? 'guide' : 'brand']" scrollbar> |
|
|
|
|
|
<div class="brand-content" ref="content"> |
|
|
|
|
|
<div |
|
|
|
|
|
class="groups" |
|
|
|
|
|
v-for="(item, i) of list" |
|
|
|
|
|
:ref=" |
|
|
|
|
|
el => { |
|
|
|
|
|
groups[i] = el |
|
|
|
|
|
} |
|
|
|
|
|
" |
|
|
|
|
|
v-show="item.shopList.length" |
|
|
|
|
|
:key="item.name" |
|
|
> |
|
|
> |
|
|
<div class="brand-content"> |
|
|
|
|
|
<div class="groups" v-for="item of list" v-show="item.shopList.length" :key="item.name"> |
|
|
|
|
|
<h1 class="info"> |
|
|
<h1 class="info"> |
|
|
{{ item.name }}<span class="meta">/ {{ item.shopList.length }}个</span> |
|
|
{{ item.name }}<span class="meta">/ {{ item.shopList.length }}个</span> |
|
|
<span v-if="item.name === currentFloor.floor" class="current" id="current">您在本层</span> |
|
|
<span v-if="item.name === currentFloor.floor" class="current" id="current">您在本层</span> |
|
|
@ -26,22 +31,57 @@ |
|
|
</TransitionGroup> |
|
|
</TransitionGroup> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<!-- <div class="indicator" id="indicator" ref="indicatorWrapper"> |
|
|
|
|
|
<div class="handle"></div> |
|
|
|
|
|
</div> --> |
|
|
|
|
|
|
|
|
<div class="indicator" :style="{ visibility: hasScollBar ? 'visible' : 'hidden' }" id="indicator" ref="indicatorWrapper"> |
|
|
|
|
|
<div class="handle">{{ list[indicatorIndex]?.name }}</div> |
|
|
|
|
|
</div> |
|
|
</ScrollView> |
|
|
</ScrollView> |
|
|
</template> |
|
|
</template> |
|
|
|
|
|
|
|
|
<script setup> |
|
|
<script setup> |
|
|
import { ref, nextTick, watch } from 'vue' |
|
|
|
|
|
|
|
|
import { ref, nextTick, watch, computed } from 'vue' |
|
|
import ShopItem from '@/base/ShopItem/ShopItem.vue' |
|
|
import ShopItem from '@/base/ShopItem/ShopItem.vue' |
|
|
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|
|
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|
|
import { storeToRefs } from 'pinia' |
|
|
import { storeToRefs } from 'pinia' |
|
|
import { useStore } from '@/store/root' |
|
|
import { useStore } from '@/store/root' |
|
|
|
|
|
import { useElementSize, useMutationObserver } from '@vueuse/core' |
|
|
|
|
|
import { getTranslateValues } from './getTranslateValues' |
|
|
|
|
|
|
|
|
const store = useStore() |
|
|
const store = useStore() |
|
|
const { currentFloor } = storeToRefs(store) |
|
|
const { currentFloor } = storeToRefs(store) |
|
|
const indicatorWrapper = ref(null) |
|
|
const indicatorWrapper = ref(null) |
|
|
const scroll = ref(null) |
|
|
const scroll = ref(null) |
|
|
|
|
|
const content = ref(null) |
|
|
|
|
|
const groups = ref([]) |
|
|
|
|
|
const { height: containerHeight } = useElementSize(scroll) |
|
|
|
|
|
|
|
|
|
|
|
const { height: contentHeight } = useElementSize(content) |
|
|
|
|
|
const hasScollBar = computed(() => containerHeight.value < contentHeight.value) |
|
|
|
|
|
const heights = computed(() => groups.value.map(useElementSize).map(({ height }) => height)) |
|
|
|
|
|
const bounds = computed(() => |
|
|
|
|
|
heights.value.reduce((acc, nxt, i) => { |
|
|
|
|
|
const arr = [...acc] |
|
|
|
|
|
arr[i] = i === 0 ? nxt.value : arr[i - 1] + nxt.value |
|
|
|
|
|
return arr |
|
|
|
|
|
}, []) |
|
|
|
|
|
) |
|
|
|
|
|
const y = ref(0) |
|
|
|
|
|
|
|
|
|
|
|
const indicatorIndex = computed(() => |
|
|
|
|
|
bounds.value.findIndex((el, i) => { |
|
|
|
|
|
const start = 40 - y.value |
|
|
|
|
|
if (i === 0 && start < el) return true |
|
|
|
|
|
return start > bounds.value[i - 1] && start < el |
|
|
|
|
|
}) |
|
|
|
|
|
) |
|
|
|
|
|
useMutationObserver( |
|
|
|
|
|
content, |
|
|
|
|
|
([{ attributeName, target }]) => { |
|
|
|
|
|
if (attributeName === 'style') y.value = getTranslateValues(target).y |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
attributes: true |
|
|
|
|
|
} |
|
|
|
|
|
) |
|
|
const props = defineProps({ |
|
|
const props = defineProps({ |
|
|
list: Array, |
|
|
list: Array, |
|
|
config: Object, |
|
|
config: Object, |
|
|
@ -55,6 +95,7 @@ const emits = defineEmits(['click']) |
|
|
function handleShop(item) { |
|
|
function handleShop(item) { |
|
|
emits('click', item) |
|
|
emits('click', item) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
watch( |
|
|
watch( |
|
|
() => props.isRow, |
|
|
() => props.isRow, |
|
|
() => |
|
|
() => |
|
|
@ -106,11 +147,19 @@ watch([scroll, () => props.shop], () => { |
|
|
top: 102px; |
|
|
top: 102px; |
|
|
right: 43px; |
|
|
right: 43px; |
|
|
width: 77px; |
|
|
width: 77px; |
|
|
|
|
|
pointer-events: none; |
|
|
.handle { |
|
|
.handle { |
|
|
position: absolute; |
|
|
position: absolute; |
|
|
width: 77px; |
|
|
width: 77px; |
|
|
height: 32px; |
|
|
height: 32px; |
|
|
background: center / cover no-repeat url(./handle.png); |
|
|
background: center / cover no-repeat url(./handle.png); |
|
|
|
|
|
font-family: 'Montserrat'; |
|
|
|
|
|
font-style: normal; |
|
|
|
|
|
font-weight: 700; |
|
|
|
|
|
font-size: 14px; |
|
|
|
|
|
line-height: 32px; |
|
|
|
|
|
color: rgba(0, 0, 0, 0.8); |
|
|
|
|
|
text-align: center; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
&.guide { |
|
|
&.guide { |
|
|
@ -146,6 +195,7 @@ watch([scroll, () => props.shop], () => { |
|
|
background: #ffffff !important; |
|
|
background: #ffffff !important; |
|
|
border-radius: 6px !important; |
|
|
border-radius: 6px !important; |
|
|
border: none !important; |
|
|
border: none !important; |
|
|
|
|
|
margin-top: -50%; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|