|
|
@@ -4,17 +4,23 @@ import PasswordCard from './components/PasswordCard.vue'
|
|
|
import FeatureUpdateCard from './components/FeatureUpdateCard.vue'
|
|
|
import { useNotificationMessage } from '@/stores/modules/notificationMessage'
|
|
|
import { cloneDeep } from 'lodash'
|
|
|
+import { DynamicScroller, DynamicScrollerItem } from 'vue3-virtual-scroller'
|
|
|
+import 'vue3-virtual-scroller/dist/vue3-virtual-scroller.css'
|
|
|
|
|
|
const notificationMsgStore = useNotificationMessage()
|
|
|
const props = withDefaults(
|
|
|
defineProps<{
|
|
|
data: any
|
|
|
isObserver?: boolean // 是否开启监听
|
|
|
+ isScrollPadding?: boolean // 是否有padding
|
|
|
updateReadCardsOnChange?: boolean // 是否在数据变化时请求接口更新已读卡片
|
|
|
+ topOffset?: number // 应减去高度
|
|
|
}>(),
|
|
|
{
|
|
|
isObserver: true,
|
|
|
- updateReadCardsOnChange: true
|
|
|
+ isScrollPadding: false,
|
|
|
+ updateReadCardsOnChange: true,
|
|
|
+ topOffset: 220
|
|
|
}
|
|
|
)
|
|
|
const pageData = ref<any[]>([])
|
|
|
@@ -101,14 +107,19 @@ const compareIdsInArrays = (arr1, arr2) => {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
+const handleData = (data) => {
|
|
|
+ data.map((item) => {
|
|
|
+ item.id = String(Math.random()).slice(-10)
|
|
|
+ })
|
|
|
+ return data
|
|
|
+}
|
|
|
const initData = () => {
|
|
|
const watchOptions = { deep: true, immediate: true }
|
|
|
-
|
|
|
const handleDataChange = (newData, oldData) => {
|
|
|
// 如果id相等,则不需要更新页面数据
|
|
|
if (compareIdsInArrays(oldData || [], newData || [])) return
|
|
|
|
|
|
- pageData.value = cloneDeep(newData)
|
|
|
+ pageData.value = handleData(cloneDeep(newData))
|
|
|
|
|
|
// 清除旧数据中的卡片监听
|
|
|
clearReadData(oldData)
|
|
|
@@ -120,22 +131,26 @@ const initData = () => {
|
|
|
|
|
|
// 重新监听新数据中的卡片
|
|
|
nextTick(() => {
|
|
|
- watchCards()
|
|
|
+ setTimeout(() => {
|
|
|
+ watchCards()
|
|
|
+ }, 500)
|
|
|
})
|
|
|
}
|
|
|
+ // 需要监听卡片已读未读状态
|
|
|
if (props.isObserver) {
|
|
|
watch(
|
|
|
() => props.data,
|
|
|
- (newData, oldData) => {
|
|
|
- handleDataChange(newData, oldData)
|
|
|
+ (newVal, oldVal) => {
|
|
|
+ handleDataChange(newVal, oldVal)
|
|
|
},
|
|
|
watchOptions
|
|
|
)
|
|
|
} else {
|
|
|
+ // 不需要监听
|
|
|
watch(
|
|
|
() => props.data,
|
|
|
(newVal) => {
|
|
|
- pageData.value = cloneDeep(newVal)
|
|
|
+ pageData.value = handleData(cloneDeep(newVal))
|
|
|
},
|
|
|
watchOptions
|
|
|
)
|
|
|
@@ -172,30 +187,60 @@ onUnmounted(() => {
|
|
|
const handleViewMore = () => {
|
|
|
emit('viewMore')
|
|
|
}
|
|
|
+const parentHeight = computed(() => {
|
|
|
+ return (window.innerHeight || document.documentElement.clientHeight) - props.topOffset
|
|
|
+})
|
|
|
+const scrollParentBoxStyle = computed(() => {
|
|
|
+ console.log(props.topOffset, 'value')
|
|
|
+ return props.topOffset ? { height: `${parentHeight.value}px` } : {}
|
|
|
+})
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
- <div
|
|
|
- class="notification-message-card"
|
|
|
- :data-card-id="item.info.id"
|
|
|
- :data-card-isread="item.info.isRead"
|
|
|
- v-for="item in pageData"
|
|
|
- :key="item.info.id || Math.random()"
|
|
|
+ <DynamicScroller
|
|
|
+ class="scroller"
|
|
|
+ :style="scrollParentBoxStyle"
|
|
|
+ :items="pageData"
|
|
|
+ :min-item-size="100"
|
|
|
+ key-field="id"
|
|
|
>
|
|
|
- <EventCard
|
|
|
- @seeAll="handleSeeAll"
|
|
|
- @jump-tracking="emit('jumpTracking')"
|
|
|
- v-if="item.notificationType === 'event'"
|
|
|
- :data="item.info"
|
|
|
- />
|
|
|
- <PasswordCard v-else-if="item.notificationType === 'password'" :data="item.info" />
|
|
|
- <FeatureUpdateCard
|
|
|
- @view-more="handleViewMore"
|
|
|
- v-else-if="item.notificationType === 'feature'"
|
|
|
- :data="item.info"
|
|
|
- />
|
|
|
- <slot></slot>
|
|
|
- </div>
|
|
|
+ <template v-slot="{ item, index, active }">
|
|
|
+ <DynamicScrollerItem
|
|
|
+ :class="{ 'scroll-padding': props.isScrollPadding }"
|
|
|
+ :item="item"
|
|
|
+ :active="active"
|
|
|
+ :size-dependencies="[item.info.isRead]"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="notification-message-card"
|
|
|
+ :data-card-id="item.info.id"
|
|
|
+ :data-card-isread="item.info.isRead"
|
|
|
+ >
|
|
|
+ <EventCard
|
|
|
+ @seeAll="handleSeeAll"
|
|
|
+ @jump-tracking="emit('jumpTracking')"
|
|
|
+ v-if="item.notificationType === 'event'"
|
|
|
+ :data="item.info"
|
|
|
+ />
|
|
|
+ <PasswordCard v-else-if="item.notificationType === 'password'" :data="item.info" />
|
|
|
+ <FeatureUpdateCard
|
|
|
+ @view-more="handleViewMore"
|
|
|
+ v-else-if="item.notificationType === 'feature'"
|
|
|
+ :data="item.info"
|
|
|
+ />
|
|
|
+ <slot></slot>
|
|
|
+ </div>
|
|
|
+ </DynamicScrollerItem>
|
|
|
+ </template>
|
|
|
+ </DynamicScroller>
|
|
|
</template>
|
|
|
|
|
|
-<style lang="scss" scoped></style>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.scroller {
|
|
|
+ width: 100%;
|
|
|
+ overflow-y: auto;
|
|
|
+ .scroll-padding {
|
|
|
+ padding: 10px 140px 0px 16px;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|