|
|
@@ -12,11 +12,11 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 标题 -->
|
|
|
- <div class="top-center-box">
|
|
|
- <div class="top-center-inner-box" style="background-image: url('./src/assets/programming/list_title.png');">
|
|
|
- <span>{{ pageTitle }}</span>
|
|
|
- </div>
|
|
|
+ <div class="top-center-box" v-if="!showVideo">
|
|
|
+ <div class="top-center-inner-box" style="background-image: url('./src/assets/programming/list_title.png');">
|
|
|
+ <span>{{ pageTitle }}</span>
|
|
|
</div>
|
|
|
+ </div>
|
|
|
<!-- 课程提示 -->
|
|
|
<div class="top-right-box">
|
|
|
<div class="top-right-inner-box">
|
|
|
@@ -32,18 +32,14 @@
|
|
|
<el-icon class="btn-icon" :class="{ 'disabled-icon': currentIndex === 0 }"><ArrowLeftBold /></el-icon>
|
|
|
</div>
|
|
|
<div
|
|
|
- class="content-box"
|
|
|
- ref="contentBox"
|
|
|
- @mousedown="handleMouseDown"
|
|
|
- @mousemove="handleMouseMove"
|
|
|
- @mouseup="handleMouseUp"
|
|
|
- @mouseleave="handleMouseLeave"
|
|
|
- @touchstart="handleTouchStart"
|
|
|
- @touchmove="handleTouchMove"
|
|
|
- @touchend="handleTouchEnd"
|
|
|
- @touchcancel="handleTouchEnd"
|
|
|
- @scroll="handleScroll"
|
|
|
- >
|
|
|
+ class="content-box"
|
|
|
+ ref="contentBox"
|
|
|
+ @mousedown="handleMouseDown"
|
|
|
+ @mousemove="handleMouseMove"
|
|
|
+ @mouseup="handleMouseUp"
|
|
|
+ @mouseleave="handleMouseLeave"
|
|
|
+ @scroll="handleScroll"
|
|
|
+ >
|
|
|
<!-- 动态渲染课程内容 -->
|
|
|
<div
|
|
|
v-for="(item) in courseItems"
|
|
|
@@ -127,8 +123,6 @@ const isDragging = ref(false)
|
|
|
const startX = ref(0)
|
|
|
const scrollLeft = ref(0)
|
|
|
const hasMoved = ref(false) // 标记是否发生了移动
|
|
|
-const touchStartX = ref(0)
|
|
|
-const touchStartTime = ref(0)
|
|
|
|
|
|
// 获取contentBox元素的引用
|
|
|
const contentBox = ref(null)
|
|
|
@@ -144,23 +138,33 @@ const getStarCount = (contentType) => {
|
|
|
|
|
|
// 上一页
|
|
|
const prevSlide = () => {
|
|
|
- if (contentBox.value) {
|
|
|
- const scrollAmount = contentBox.value.clientWidth * 0.75
|
|
|
- contentBox.value.scrollTo({
|
|
|
- left: Math.max(0, contentBox.value.scrollLeft - scrollAmount),
|
|
|
- behavior: 'smooth'
|
|
|
- })
|
|
|
+ if (currentIndex.value > 0) {
|
|
|
+ currentIndex.value = Math.max(0, currentIndex.value - 3)
|
|
|
+ // 滚动到对应位置
|
|
|
+ if (contentBox.value) {
|
|
|
+ const itemWidth = rpxValue(140) + rpxValue(70); // 宽度+间距
|
|
|
+ const scrollPosition = currentIndex.value * itemWidth;
|
|
|
+ contentBox.value.scrollTo({
|
|
|
+ left: scrollPosition,
|
|
|
+ behavior: 'smooth'
|
|
|
+ });
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 下一页
|
|
|
const nextSlide = () => {
|
|
|
- if (contentBox.value) {
|
|
|
- const scrollAmount = contentBox.value.clientWidth * 0.75
|
|
|
- contentBox.value.scrollTo({
|
|
|
- left: contentBox.value.scrollLeft + scrollAmount,
|
|
|
- behavior: 'smooth'
|
|
|
- })
|
|
|
+ if (currentIndex.value < courseItems.value.length - 3) {
|
|
|
+ currentIndex.value = Math.min(courseItems.value.length - 3, currentIndex.value + 3)
|
|
|
+ // 滚动到对应位置
|
|
|
+ if (contentBox.value) {
|
|
|
+ const itemWidth = rpxValue(140) + rpxValue(70); // 宽度+间距
|
|
|
+ const scrollPosition = currentIndex.value * itemWidth;
|
|
|
+ contentBox.value.scrollTo({
|
|
|
+ left: scrollPosition,
|
|
|
+ behavior: 'smooth'
|
|
|
+ });
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -191,8 +195,7 @@ const handleMouseMove = (e) => {
|
|
|
}
|
|
|
|
|
|
// 鼠标松开事件处理函数
|
|
|
-const handleMouseUp = (e) => {
|
|
|
- e.stopPropagation()
|
|
|
+const handleMouseUp = () => {
|
|
|
isDragging.value = false
|
|
|
// 延迟重置hasMoved,确保点击事件可以正常判断
|
|
|
setTimeout(() => {
|
|
|
@@ -206,70 +209,33 @@ const handleMouseLeave = () => {
|
|
|
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 = contentBox.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()
|
|
|
- // 设置滚动位置
|
|
|
- contentBox.value.scrollLeft = scrollLeft.value + diffX
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 触摸结束事件处理函数(支持移动设备)
|
|
|
-const handleTouchEnd = (e) => {
|
|
|
- e.stopPropagation()
|
|
|
- isDragging.value = false
|
|
|
- // 延迟重置hasMoved
|
|
|
- setTimeout(() => {
|
|
|
- hasMoved.value = false
|
|
|
- }, 100)
|
|
|
-}
|
|
|
-
|
|
|
-// 节流函数 - 限制函数在一段时间内只能执行一次
|
|
|
-const throttle = (func, limit) => {
|
|
|
- let inThrottle
|
|
|
- return function() {
|
|
|
- const args = arguments
|
|
|
- const context = this
|
|
|
- if (!inThrottle) {
|
|
|
- func.apply(context, args)
|
|
|
- inThrottle = true
|
|
|
- setTimeout(() => {
|
|
|
- inThrottle = false
|
|
|
- }, limit)
|
|
|
+// rpx转换为像素值的辅助函数
|
|
|
+const rpxValue = (px) => {
|
|
|
+ return (px / 750) * window.innerWidth;
|
|
|
+}
|
|
|
+
|
|
|
+// 滚动事件处理函数
|
|
|
+const handleScroll = () => {
|
|
|
+ if (contentBox.value && !isDragging.value) {
|
|
|
+ // 检查是否滚动到最右侧
|
|
|
+ const { scrollLeft, scrollWidth, clientWidth } = contentBox.value;
|
|
|
+ // 当滚动到最右侧时,禁用右侧箭头
|
|
|
+ if (scrollLeft + clientWidth >= scrollWidth - 10) {
|
|
|
+ currentIndex.value = Math.max(0, courseItems.value.length - 3);
|
|
|
+ } else {
|
|
|
+ // 向右滑动,左侧按钮正常显示
|
|
|
+ if (scrollLeft > 10) {
|
|
|
+ // 根据滚动位置计算当前索引,但不限制为0
|
|
|
+ const itemWidth = rpxValue(140) + rpxValue(70); // 宽度+间距
|
|
|
+ const calculatedIndex = Math.round(scrollLeft / itemWidth);
|
|
|
+ currentIndex.value = Math.max(0, Math.min(courseItems.value.length - 3, calculatedIndex));
|
|
|
+ } else { // 滚动到最左侧
|
|
|
+ currentIndex.value = 0;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 优化的滚动事件处理函数
|
|
|
-let animationFrameId = null
|
|
|
-const handleScroll = throttle(() => {
|
|
|
- // 取消之前的动画帧请求
|
|
|
- if (animationFrameId) {
|
|
|
- cancelAnimationFrame(animationFrameId)
|
|
|
- }
|
|
|
-}, 16) // 约60fps的频率
|
|
|
-
|
|
|
// 组件挂载时获取路由参数设置标题
|
|
|
onMounted(() => {
|
|
|
// 检查路由参数中是否有courseTitle
|
|
|
@@ -391,18 +357,24 @@ const goBackIndex = () => {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
background-size: 70%;
|
|
|
- background-position: 50% 80%;
|
|
|
- background-repeat: no-repeat;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- cursor: pointer;
|
|
|
-
|
|
|
- span{
|
|
|
- font-size: rpx(15);
|
|
|
- color: white;
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-position: center center; /* 背景图垂直水平居中 */
|
|
|
+ display: flex;
|
|
|
+ align-items: center; /* 垂直居中 */
|
|
|
+ justify-content: center; /* 水平居中 */
|
|
|
+ cursor: pointer;
|
|
|
+ position: relative; /* 相对定位 */
|
|
|
+ span{
|
|
|
+ font-size: rpx(16);
|
|
|
+ color: white;
|
|
|
+ position: relative;
|
|
|
+ z-index: 1; /* 确保文字在背景图上方 */
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding-bottom: rpx(5);
|
|
|
+ }
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
.top-left-inner-box{
|
|
|
display: flex;
|
|
|
@@ -469,7 +441,7 @@ const goBackIndex = () => {
|
|
|
padding: 0 rpx(30);
|
|
|
/* 设置背景图 */
|
|
|
background-image: url('@/assets/programming/track01.png');
|
|
|
- background-size: rpx(1360) rpx(350); /* 使用固定宽度,背景图大小始终一致 */
|
|
|
+ background-size: rpx(1360) rpx(350); /* 使用固定宽度,背景图大小一致 */
|
|
|
background-position: left calc(-1 * rpx(50));
|
|
|
background-repeat: no-repeat;
|
|
|
background-attachment: local; /* 背景图跟内容一起滚动 */
|
|
|
@@ -517,12 +489,12 @@ const goBackIndex = () => {
|
|
|
/* 鼠标悬停放大效果 - 在保持原有垂直位置的基础上放大 */
|
|
|
.slide-item:nth-child(odd):hover {
|
|
|
transform: translateY(-50%) scale(1.1);
|
|
|
- z-index: 10; /* 确保放大时在顶层显示 */
|
|
|
+ z-index: 10;
|
|
|
}
|
|
|
|
|
|
.slide-item:nth-child(even):hover {
|
|
|
transform: translateY(50%) scale(1.1);
|
|
|
- z-index: 10; /* 确保放大时在顶层显示 */
|
|
|
+ z-index: 10;
|
|
|
}
|
|
|
|
|
|
/* 内容样式 */
|