|
@@ -31,13 +31,10 @@
|
|
|
class="middle-box"
|
|
class="middle-box"
|
|
|
ref="middleBox"
|
|
ref="middleBox"
|
|
|
@mousedown="handleMouseDown"
|
|
@mousedown="handleMouseDown"
|
|
|
- @mousemove="handleMouseMove"
|
|
|
|
|
- @mouseup="handleMouseUp"
|
|
|
|
|
- @mouseleave="handleMouseLeave"
|
|
|
|
|
- @touchstart="handleTouchStart"
|
|
|
|
|
- @touchmove="handleTouchMove"
|
|
|
|
|
- @touchend="handleTouchEnd"
|
|
|
|
|
- @touchcancel="handleTouchEnd"
|
|
|
|
|
|
|
+ @mousemove="handleMouseMove"
|
|
|
|
|
+ @mouseup="handleMouseUp"
|
|
|
|
|
+ @mouseleave="handleMouseLeave"
|
|
|
|
|
+ @scroll="handleScroll"
|
|
|
>
|
|
>
|
|
|
<div
|
|
<div
|
|
|
v-for="(courseType, index) in specificCourses"
|
|
v-for="(courseType, index) in specificCourses"
|
|
@@ -183,11 +180,17 @@ const circleButtons = reactive(specificCourses.map((_, index) => ({ text: String
|
|
|
// 自动滚动到中间位置
|
|
// 自动滚动到中间位置
|
|
|
watch(activeButton, (newIndex) => {
|
|
watch(activeButton, (newIndex) => {
|
|
|
if (middleBox.value && newIndex !== -1) {
|
|
if (middleBox.value && newIndex !== -1) {
|
|
|
|
|
+ const containerWidth = middleBox.value.clientWidth;
|
|
|
|
|
+ const calculatedIndex = Math.max(0, Math.min(
|
|
|
|
|
+ specificCourses.length - 3,
|
|
|
|
|
+ Math.round(newIndex / 3) * 3
|
|
|
|
|
+ ));
|
|
|
|
|
+ currentIndex.value = calculatedIndex;
|
|
|
|
|
+
|
|
|
// 找到对应的课程卡片元素
|
|
// 找到对应的课程卡片元素
|
|
|
const courseElement = middleBox.value.querySelector(`.middle-inner-box:nth-child(${newIndex + 1})`);
|
|
const courseElement = middleBox.value.querySelector(`.middle-inner-box:nth-child(${newIndex + 1})`);
|
|
|
if (courseElement) {
|
|
if (courseElement) {
|
|
|
// 计算滚动位置,选中的卡片居中
|
|
// 计算滚动位置,选中的卡片居中
|
|
|
- const containerWidth = middleBox.value.clientWidth;
|
|
|
|
|
const elementLeft = courseElement.offsetLeft;
|
|
const elementLeft = courseElement.offsetLeft;
|
|
|
const elementWidth = courseElement.offsetWidth;
|
|
const elementWidth = courseElement.offsetWidth;
|
|
|
// 计算居中位置
|
|
// 计算居中位置
|
|
@@ -205,97 +208,60 @@ watch(activeButton, (newIndex) => {
|
|
|
const isDragging = ref(false)
|
|
const isDragging = ref(false)
|
|
|
const startX = ref(0)
|
|
const startX = ref(0)
|
|
|
const scrollLeft = ref(0)
|
|
const scrollLeft = ref(0)
|
|
|
-const hasMoved = ref(false) // 标记是否发生了移动
|
|
|
|
|
-const touchStartX = ref(0)
|
|
|
|
|
-const touchStartTime = ref(0)
|
|
|
|
|
|
|
|
|
|
// 鼠标按下事件处理函数
|
|
// 鼠标按下事件处理函数
|
|
|
const handleMouseDown = (e) => {
|
|
const handleMouseDown = (e) => {
|
|
|
isDragging.value = true
|
|
isDragging.value = true
|
|
|
- hasMoved.value = false
|
|
|
|
|
startX.value = e.pageX - middleBox.value.offsetLeft
|
|
startX.value = e.pageX - middleBox.value.offsetLeft
|
|
|
scrollLeft.value = middleBox.value.scrollLeft
|
|
scrollLeft.value = middleBox.value.scrollLeft
|
|
|
- e.stopPropagation() // 阻止事件冒泡
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 鼠标移动事件处理函数
|
|
// 鼠标移动事件处理函数
|
|
|
const handleMouseMove = (e) => {
|
|
const handleMouseMove = (e) => {
|
|
|
if (!isDragging.value) return
|
|
if (!isDragging.value) return
|
|
|
-
|
|
|
|
|
- // 标记已发生移动
|
|
|
|
|
- hasMoved.value = true
|
|
|
|
|
-
|
|
|
|
|
- // 阻止默认行为和冒泡
|
|
|
|
|
e.preventDefault()
|
|
e.preventDefault()
|
|
|
- e.stopPropagation()
|
|
|
|
|
-
|
|
|
|
|
const x = e.pageX - middleBox.value.offsetLeft
|
|
const x = e.pageX - middleBox.value.offsetLeft
|
|
|
const walk = (x - startX.value) * 2 // 滚动速度
|
|
const walk = (x - startX.value) * 2 // 滚动速度
|
|
|
middleBox.value.scrollLeft = scrollLeft.value - walk
|
|
middleBox.value.scrollLeft = scrollLeft.value - walk
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 鼠标松开事件处理函数
|
|
// 鼠标松开事件处理函数
|
|
|
-const handleMouseUp = (e) => {
|
|
|
|
|
- e.stopPropagation()
|
|
|
|
|
|
|
+const handleMouseUp = () => {
|
|
|
isDragging.value = false
|
|
isDragging.value = false
|
|
|
- // 延迟重置hasMoved,确保点击事件可以正常判断
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- hasMoved.value = false
|
|
|
|
|
- }, 100)
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 鼠标离开事件处理函数
|
|
// 鼠标离开事件处理函数
|
|
|
const handleMouseLeave = () => {
|
|
const handleMouseLeave = () => {
|
|
|
isDragging.value = false
|
|
isDragging.value = false
|
|
|
- hasMoved.value = false
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 触摸开始事件处理函数(支持移动设备)
|
|
|
|
|
-const handleTouchStart = (e) => {
|
|
|
|
|
- const touch = e.touches[0]
|
|
|
|
|
- isDragging.value = true
|
|
|
|
|
- hasMoved.value = false
|
|
|
|
|
- touchStartX.value = touch.clientX
|
|
|
|
|
- touchStartTime.value = Date.now()
|
|
|
|
|
- scrollLeft.value = middleBox.value.scrollLeft
|
|
|
|
|
- e.stopPropagation()
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// 触摸移动事件处理函数(支持移动设备)
|
|
|
|
|
-const handleTouchMove = (e) => {
|
|
|
|
|
- if (!isDragging.value) return
|
|
|
|
|
-
|
|
|
|
|
- const touch = e.touches[0]
|
|
|
|
|
- const diffX = touchStartX.value - touch.clientX
|
|
|
|
|
-
|
|
|
|
|
- // 判断是否为有效的水平滑动
|
|
|
|
|
- if (Math.abs(diffX) > 5) {
|
|
|
|
|
- hasMoved.value = true
|
|
|
|
|
-
|
|
|
|
|
- // 阻止默认行为和冒泡
|
|
|
|
|
- e.preventDefault()
|
|
|
|
|
- e.stopPropagation()
|
|
|
|
|
-
|
|
|
|
|
- // 设置滚动位置
|
|
|
|
|
- middleBox.value.scrollLeft = scrollLeft.value + diffX
|
|
|
|
|
|
|
+// 滚动事件处理函数
|
|
|
|
|
+const handleScroll = () => {
|
|
|
|
|
+ if (middleBox.value && !isDragging.value) {
|
|
|
|
|
+ // 检查是否滚动到最右侧
|
|
|
|
|
+ const { scrollLeft, scrollWidth, clientWidth } = middleBox.value;
|
|
|
|
|
+ // 当滚动到最右侧时,禁用右侧箭头
|
|
|
|
|
+ if (scrollLeft + clientWidth >= scrollWidth - 10) {
|
|
|
|
|
+ currentIndex.value = Math.max(0, specificCourses.length - 3);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 向右滑动,左侧按钮正常显示
|
|
|
|
|
+ if (scrollLeft > 10) {
|
|
|
|
|
+ // 根据滚动位置计算当前索引,但不限制为0
|
|
|
|
|
+ currentIndex.value = Math.max(0, Math.min(
|
|
|
|
|
+ specificCourses.length - 3,
|
|
|
|
|
+ Math.round(scrollLeft / (clientWidth * 0.75))
|
|
|
|
|
+ ));
|
|
|
|
|
+ } else { // 滚动到最左侧
|
|
|
|
|
+ currentIndex.value = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// 触摸结束事件处理函数(支持移动设备)
|
|
|
|
|
-const handleTouchEnd = (e) => {
|
|
|
|
|
- e.stopPropagation()
|
|
|
|
|
- isDragging.value = false
|
|
|
|
|
- // 延迟重置hasMoved
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- hasMoved.value = false
|
|
|
|
|
- }, 100)
|
|
|
|
|
-}
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
// 处理项目点击事件
|
|
// 处理项目点击事件
|
|
|
const handleItemClick = (courseType, index) => {
|
|
const handleItemClick = (courseType, index) => {
|
|
|
- // 如果在拖动过程中,则不触发点击事件
|
|
|
|
|
- if (hasMoved.value) return
|
|
|
|
|
-
|
|
|
|
|
// 调用原始的goToProgrammingList函数
|
|
// 调用原始的goToProgrammingList函数
|
|
|
goToProgrammingList(courseType, index)
|
|
goToProgrammingList(courseType, index)
|
|
|
}
|
|
}
|
|
@@ -444,15 +410,23 @@ const disableBlockly = (blocklyId = categoryId.value) => {
|
|
|
height: 100%;
|
|
height: 100%;
|
|
|
}
|
|
}
|
|
|
.top-center-inner-box{
|
|
.top-center-inner-box{
|
|
|
- background-size: 70%;
|
|
|
|
|
- background-position: 50% 80%;
|
|
|
|
|
|
|
+ background-size: 70%;
|
|
|
background-repeat: no-repeat;
|
|
background-repeat: no-repeat;
|
|
|
- display: flex; /* 使用flex布局 */
|
|
|
|
|
|
|
+ background-position: center center; /* 背景图垂直水平居中 */
|
|
|
|
|
+ display: flex;
|
|
|
align-items: center; /* 垂直居中 */
|
|
align-items: center; /* 垂直居中 */
|
|
|
justify-content: center; /* 水平居中 */
|
|
justify-content: center; /* 水平居中 */
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ position: relative; /* 相对定位 */
|
|
|
span{
|
|
span{
|
|
|
- font-size: rpx(17);
|
|
|
|
|
|
|
+ font-size: rpx(16);
|
|
|
color: white;
|
|
color: white;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ z-index: 1; /* 确保文字在背景图上方 */
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ padding-bottom: rpx(5);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
.top-left-inner-box{
|
|
.top-left-inner-box{
|
|
@@ -473,7 +447,7 @@ const disableBlockly = (blocklyId = categoryId.value) => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.middle-wrapper {
|
|
.middle-wrapper {
|
|
|
- height: 60%;
|
|
|
|
|
|
|
+ height: 80%;
|
|
|
overflow: hidden; /* 溢出隐藏 */
|
|
overflow: hidden; /* 溢出隐藏 */
|
|
|
position: relative;
|
|
position: relative;
|
|
|
display: flex;
|
|
display: flex;
|
|
@@ -492,23 +466,18 @@ const disableBlockly = (blocklyId = categoryId.value) => {
|
|
|
-webkit-overflow-scrolling: touch; /* 触摸设备支持 */
|
|
-webkit-overflow-scrolling: touch; /* 触摸设备支持 */
|
|
|
position: relative;
|
|
position: relative;
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
- cursor: grab; /* 显示可抓取图标 */
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/* 鼠标按下时的光标样式 */
|
|
|
|
|
-.middle-box:active {
|
|
|
|
|
- cursor: grabbing;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.middle-inner-box{
|
|
.middle-inner-box{
|
|
|
- width: rpx(130); /* 设置固定宽度 */
|
|
|
|
|
|
|
+ width: rpx(140); /* 设置固定宽度 */
|
|
|
height: 100%; /* 设置固定高度 */
|
|
height: 100%; /* 设置固定高度 */
|
|
|
position: relative;
|
|
position: relative;
|
|
|
- cursor: pointer; /* 显示可抓取图标 */
|
|
|
|
|
|
|
+ cursor: pointer;
|
|
|
user-select: none; /* 禁止文本选择 */
|
|
user-select: none; /* 禁止文本选择 */
|
|
|
- display: inline-block; /* 水平排列 */
|
|
|
|
|
- margin-right: rpx(20);
|
|
|
|
|
- margin-left: rpx(15);
|
|
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ align-items: center; /* 垂直居中 */
|
|
|
|
|
+ justify-content: center; /* 水平居中 */
|
|
|
|
|
+ margin-left: rpx(30);
|
|
|
vertical-align: middle; /* 垂直居中对齐 */
|
|
vertical-align: middle; /* 垂直居中对齐 */
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -530,8 +499,7 @@ const disableBlockly = (blocklyId = categoryId.value) => {
|
|
|
|
|
|
|
|
.new-white-box {
|
|
.new-white-box {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
- height: 65%;
|
|
|
|
|
- margin-top: rpx(20);
|
|
|
|
|
|
|
+ height: rpx(150);
|
|
|
background-color: white;
|
|
background-color: white;
|
|
|
border-radius: rpx(15);
|
|
border-radius: rpx(15);
|
|
|
display: flex;
|
|
display: flex;
|
|
@@ -600,9 +568,10 @@ const disableBlockly = (blocklyId = categoryId.value) => {
|
|
|
|
|
|
|
|
/* 背景图容器 */
|
|
/* 背景图容器 */
|
|
|
.bg-image-container {
|
|
.bg-image-container {
|
|
|
- width: 100%;
|
|
|
|
|
- height: 85%;
|
|
|
|
|
- background-size: 105%;
|
|
|
|
|
|
|
+ width: rpx(140);
|
|
|
|
|
+ height: rpx(150);
|
|
|
|
|
+ margin-top: rpx(5);
|
|
|
|
|
+ background-size: 100%;
|
|
|
background-position: center;
|
|
background-position: center;
|
|
|
background-repeat: no-repeat;
|
|
background-repeat: no-repeat;
|
|
|
position: relative;
|
|
position: relative;
|
|
@@ -618,6 +587,8 @@ const disableBlockly = (blocklyId = categoryId.value) => {
|
|
|
background-position: center;
|
|
background-position: center;
|
|
|
background-repeat: no-repeat;
|
|
background-repeat: no-repeat;
|
|
|
z-index: 1;
|
|
z-index: 1;
|
|
|
|
|
+ transform-origin: left;
|
|
|
|
|
+ transform: scale(0.91);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* 文字容器 */
|
|
/* 文字容器 */
|