|
|
@@ -3,9 +3,15 @@
|
|
|
<!-- 顶部导航和搜索区域 -->
|
|
|
<div class="top-section">
|
|
|
<!-- 顶部导航栏 -->
|
|
|
- <div class="nav-scroll-container">
|
|
|
- <el-menu :default-active="activeCategory" class="category-menu" mode="horizontal" :ellipsis="false"
|
|
|
- background-color="#f8f3e8" @select="handleCategorySelect">
|
|
|
+ <div class="nav-scroll-container" ref="navScrollContainer">
|
|
|
+ <el-menu
|
|
|
+ :default-active="activeCategory"
|
|
|
+ class="category-menu"
|
|
|
+ mode="horizontal"
|
|
|
+ :ellipsis="false"
|
|
|
+ background-color="#f8f3e8"
|
|
|
+ @select="handleCategorySelect"
|
|
|
+ >
|
|
|
<el-menu-item index="all"><span class="category-text">全部</span></el-menu-item>
|
|
|
<el-menu-item v-for="(category, index) in categories" :key="index" :index="category.id">
|
|
|
<span class="category-text">{{ category.name }}</span>
|
|
|
@@ -15,14 +21,21 @@
|
|
|
|
|
|
<!-- 搜索框 -->
|
|
|
<div class="search-container-collect">
|
|
|
- <el-input id="realy-input" v-model="searchText" placeholder="请输入要搜索的内容..." class="search-input" clearable>
|
|
|
+ <el-input
|
|
|
+ id="realy-input"
|
|
|
+ v-model="searchText"
|
|
|
+ placeholder="请输入要搜索的内容..."
|
|
|
+ class="search-input"
|
|
|
+ clearable
|
|
|
+ >
|
|
|
<template #suffix>
|
|
|
<el-icon :size="16">
|
|
|
<Search />
|
|
|
</el-icon>
|
|
|
</template>
|
|
|
</el-input>
|
|
|
- <div id="vir-input" class="vir-input">请输入要搜索的内容...
|
|
|
+ <div id="vir-input" class="vir-input">
|
|
|
+ 请输入要搜索的内容...
|
|
|
<el-icon class="vir-icon" :size="16">
|
|
|
<Search />
|
|
|
</el-icon>
|
|
|
@@ -33,12 +46,24 @@
|
|
|
<!-- 内容区域 -->
|
|
|
<div class="content-section" ref="contentSection">
|
|
|
<div class="collection-list">
|
|
|
- <div class="collection-item" v-for="(item, index) in artifactList" :key="item.artifactId || index">
|
|
|
+ <div
|
|
|
+ class="collection-item"
|
|
|
+ v-for="(item, index) in artifactList"
|
|
|
+ :key="item.artifactId || index"
|
|
|
+ >
|
|
|
<div class="item-image-container">
|
|
|
- <img :src="getFieldValue(item, 'image') || getFieldValue(item, 'img') || '@/assets/indexPage/zhanweitu.png'"
|
|
|
- alt="藏品图片" class="item-image" />
|
|
|
+ <img
|
|
|
+ :src="
|
|
|
+ getFieldValue(item, 'image') ||
|
|
|
+ getFieldValue(item, 'img') ||
|
|
|
+ '@/assets/indexPage/zhanweitu.png'
|
|
|
+ "
|
|
|
+ alt="藏品图片"
|
|
|
+ class="item-image"
|
|
|
+ />
|
|
|
<div class="view-button" @click="goCollectDetail(item)">
|
|
|
- <span>查看</span><el-icon>
|
|
|
+ <span>查看</span
|
|
|
+ ><el-icon>
|
|
|
<Right />
|
|
|
</el-icon>
|
|
|
</div>
|
|
|
@@ -70,7 +95,7 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, onMounted, computed, watch, nextTick } from 'vue'
|
|
|
+import { ref, onMounted, onUnmounted, computed, watch, nextTick } from 'vue'
|
|
|
import { Search } from '@element-plus/icons-vue'
|
|
|
import { useRouter, useRoute } from 'vue-router'
|
|
|
import { useStore } from 'vuex'
|
|
|
@@ -97,17 +122,8 @@ const getFieldValue = (item, fieldName) => {
|
|
|
}
|
|
|
|
|
|
// 使用典藏API组合式函数
|
|
|
-const {
|
|
|
- artifactList,
|
|
|
- loading,
|
|
|
- hasMore,
|
|
|
- searchTitle,
|
|
|
- selectedType,
|
|
|
- searchArtifacts,
|
|
|
- changeType,
|
|
|
- loadMore,
|
|
|
- initData
|
|
|
-} = useCollectionApi({ isPreviewMode })
|
|
|
+const { artifactList, loading, hasMore, searchArtifacts, changeType, loadMore, initData } =
|
|
|
+ useCollectionApi({ isPreviewMode })
|
|
|
|
|
|
// 搜索文本
|
|
|
const searchText = ref('')
|
|
|
@@ -118,11 +134,15 @@ const activeCategory = ref('all')
|
|
|
// 内容区域引用
|
|
|
const contentSection = ref(null)
|
|
|
|
|
|
+// 导航滚动容器引用
|
|
|
+const navScrollContainer = ref(null)
|
|
|
+
|
|
|
// 分类数据
|
|
|
const categories = [
|
|
|
- { id: '1', name: '平面纸质类' },
|
|
|
- { id: '2', name: '棉麻丝绸类' },
|
|
|
- { id: '3', name: '专业器物类' },
|
|
|
+ { id: '1', name: '织绣' },
|
|
|
+ { id: '2', name: '铁器、其他金属器' },
|
|
|
+ { id: '3', name: '文物、宣传品' },
|
|
|
+ { id: '4', name: '其他' },
|
|
|
]
|
|
|
|
|
|
// 监听搜索文本变化
|
|
|
@@ -132,6 +152,11 @@ watch(searchText, async (newValue) => {
|
|
|
|
|
|
// 处理分类选择
|
|
|
const handleCategorySelect = async (index) => {
|
|
|
+ // 如果刚刚完成拖拽,忽略点击事件
|
|
|
+ if (justDragged.value) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
activeCategory.value = index
|
|
|
const typeId = index === 'all' ? 0 : parseInt(index)
|
|
|
await changeType(typeId)
|
|
|
@@ -140,7 +165,7 @@ const handleCategorySelect = async (index) => {
|
|
|
// 跳转到藏品详情页
|
|
|
const goCollectDetail = (item) => {
|
|
|
const query = {
|
|
|
- id: item.artifactId
|
|
|
+ id: item.artifactId,
|
|
|
}
|
|
|
|
|
|
// 如果当前URL有preview=1参数,则在跳转时保留
|
|
|
@@ -150,7 +175,7 @@ const goCollectDetail = (item) => {
|
|
|
|
|
|
router.push({
|
|
|
path: '/collectDetail',
|
|
|
- query: query
|
|
|
+ query: query,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
@@ -166,6 +191,77 @@ const handleScroll = async () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 导航拖拽滚动相关变量
|
|
|
+const isMouseDown = ref(false)
|
|
|
+const isDragging = ref(false)
|
|
|
+const startX = ref(0)
|
|
|
+const currentX = ref(0)
|
|
|
+const scrollLeft = ref(0)
|
|
|
+const dragThreshold = 5 // 拖拽阈值,移动超过5px才算拖拽
|
|
|
+const justDragged = ref(false) // 标记是否刚刚完成拖拽
|
|
|
+
|
|
|
+// 鼠标按下事件
|
|
|
+const handleMouseDown = (e) => {
|
|
|
+ if (!navScrollContainer.value) return
|
|
|
+
|
|
|
+ isMouseDown.value = true
|
|
|
+ isDragging.value = false
|
|
|
+ startX.value = e.pageX - navScrollContainer.value.offsetLeft
|
|
|
+ currentX.value = startX.value
|
|
|
+ scrollLeft.value = navScrollContainer.value.scrollLeft
|
|
|
+
|
|
|
+ // 不立即阻止默认行为,让点击事件能正常触发
|
|
|
+}
|
|
|
+
|
|
|
+// 鼠标移动事件
|
|
|
+const handleMouseMove = (e) => {
|
|
|
+ if (!isMouseDown.value || !navScrollContainer.value) return
|
|
|
+
|
|
|
+ currentX.value = e.pageX - navScrollContainer.value.offsetLeft
|
|
|
+ const distance = Math.abs(currentX.value - startX.value)
|
|
|
+
|
|
|
+ // 只有移动距离超过阈值才开始拖拽
|
|
|
+ if (!isDragging.value && distance > dragThreshold) {
|
|
|
+ isDragging.value = true
|
|
|
+ navScrollContainer.value.classList.add('dragging')
|
|
|
+ // 现在才阻止默认行为
|
|
|
+ e.preventDefault()
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isDragging.value) {
|
|
|
+ e.preventDefault()
|
|
|
+ const walk = (currentX.value - startX.value) * 2 // 乘以2增加滚动速度
|
|
|
+ navScrollContainer.value.scrollLeft = scrollLeft.value - walk
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 鼠标松开事件
|
|
|
+const handleMouseUp = () => {
|
|
|
+ // 如果发生了拖拽,标记为刚刚拖拽过
|
|
|
+ if (isDragging.value) {
|
|
|
+ justDragged.value = true
|
|
|
+ // 50ms后清除标记,确保不影响后续正常点击
|
|
|
+ setTimeout(() => {
|
|
|
+ justDragged.value = false
|
|
|
+ }, 50)
|
|
|
+ }
|
|
|
+
|
|
|
+ isMouseDown.value = false
|
|
|
+ isDragging.value = false
|
|
|
+ if (navScrollContainer.value) {
|
|
|
+ navScrollContainer.value.classList.remove('dragging')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 鼠标离开容器事件
|
|
|
+const handleMouseLeave = () => {
|
|
|
+ isMouseDown.value = false
|
|
|
+ isDragging.value = false
|
|
|
+ if (navScrollContainer.value) {
|
|
|
+ navScrollContainer.value.classList.remove('dragging')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// 初始化
|
|
|
onMounted(async () => {
|
|
|
await initData()
|
|
|
@@ -175,6 +271,43 @@ onMounted(async () => {
|
|
|
if (contentSection.value) {
|
|
|
contentSection.value.addEventListener('scroll', handleScroll)
|
|
|
}
|
|
|
+
|
|
|
+ // 添加导航拖拽滚动功能(仅在非移动设备上)
|
|
|
+ if (navScrollContainer.value && !('ontouchstart' in window)) {
|
|
|
+ const container = navScrollContainer.value
|
|
|
+
|
|
|
+ // 鼠标按下事件绑定在容器上
|
|
|
+ container.addEventListener('mousedown', handleMouseDown)
|
|
|
+
|
|
|
+ // 鼠标移动和松开事件绑定在document上,确保即使移出容器也能正确处理
|
|
|
+ document.addEventListener('mousemove', handleMouseMove)
|
|
|
+ document.addEventListener('mouseup', handleMouseUp)
|
|
|
+
|
|
|
+ // 鼠标离开容器事件
|
|
|
+ container.addEventListener('mouseleave', handleMouseLeave)
|
|
|
+
|
|
|
+ // 阻止默认的图片拖拽等行为
|
|
|
+ container.addEventListener('dragstart', (e) => e.preventDefault())
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 组件销毁时清理事件监听器
|
|
|
+onUnmounted(() => {
|
|
|
+ if (navScrollContainer.value && !('ontouchstart' in window)) {
|
|
|
+ const container = navScrollContainer.value
|
|
|
+
|
|
|
+ container.removeEventListener('mousedown', handleMouseDown)
|
|
|
+ container.removeEventListener('mouseleave', handleMouseLeave)
|
|
|
+ container.removeEventListener('dragstart', (e) => e.preventDefault())
|
|
|
+
|
|
|
+ // 移除document上的事件监听
|
|
|
+ document.removeEventListener('mousemove', handleMouseMove)
|
|
|
+ document.removeEventListener('mouseup', handleMouseUp)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (contentSection.value) {
|
|
|
+ contentSection.value.removeEventListener('scroll', handleScroll)
|
|
|
+ }
|
|
|
})
|
|
|
</script>
|
|
|
<style>
|
|
|
@@ -184,17 +317,17 @@ onMounted(async () => {
|
|
|
|
|
|
.search-container-collect .search-input {
|
|
|
border-radius: 20px;
|
|
|
- border-color: #5B472E;
|
|
|
+ border-color: #5b472e;
|
|
|
}
|
|
|
|
|
|
.vir-input {
|
|
|
display: none;
|
|
|
position: relative;
|
|
|
border-radius: 20px;
|
|
|
- border: 1px solid #5B472E;
|
|
|
+ border: 1px solid #5b472e;
|
|
|
height: 45px;
|
|
|
align-items: center;
|
|
|
- color: #5B472E;
|
|
|
+ color: #5b472e;
|
|
|
padding: 0 15px;
|
|
|
}
|
|
|
|
|
|
@@ -245,11 +378,27 @@ onMounted(async () => {
|
|
|
-webkit-overflow-scrolling: touch;
|
|
|
scrollbar-width: none;
|
|
|
/* Firefox */
|
|
|
+ user-select: none; /* 防止拖拽时选中文本 */
|
|
|
+ -webkit-user-select: none;
|
|
|
+ -moz-user-select: none;
|
|
|
+ -ms-user-select: none;
|
|
|
+ cursor: grab; /* 默认显示可拖拽的鼠标样式 */
|
|
|
|
|
|
&::-webkit-scrollbar {
|
|
|
display: none;
|
|
|
/* Chrome, Safari, Edge */
|
|
|
}
|
|
|
+
|
|
|
+ /* 拖拽时的样式 */
|
|
|
+ &.dragging {
|
|
|
+ cursor: grabbing !important;
|
|
|
+ user-select: none; /* 拖拽时防止选中文本 */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 移动设备不显示拖拽鼠标样式 */
|
|
|
+ @media (hover: none) and (pointer: coarse) {
|
|
|
+ cursor: default;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
:deep(.category-menu) {
|
|
|
@@ -274,17 +423,17 @@ onMounted(async () => {
|
|
|
|
|
|
.category-text {
|
|
|
display: inline-flex;
|
|
|
- border-bottom: 1px solid #F3B200;
|
|
|
+ border-bottom: 1px solid #f3b200;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
&:hover {
|
|
|
- color: #B1967B;
|
|
|
+ color: #b1967b;
|
|
|
background-color: transparent;
|
|
|
}
|
|
|
|
|
|
&:focus {
|
|
|
- color: #B1967B;
|
|
|
+ color: #b1967b;
|
|
|
background-color: transparent;
|
|
|
}
|
|
|
|
|
|
@@ -413,4 +562,4 @@ onMounted(async () => {
|
|
|
transform: rotate(360deg);
|
|
|
}
|
|
|
}
|
|
|
-</style>
|
|
|
+</style>
|