531 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			531 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| (function (win) {
 | |
|     // 初始化样式和方法
 | |
| 
 | |
|     console.log("courseHomeStyle init", win, win.location.href,);
 | |
| 
 | |
|     if (win.location.href.indexOf("courseHome.html") !== -1) {
 | |
|         // 1、导航条切换
 | |
|         initNav();
 | |
| 
 | |
|         // 2、左 侧边栏
 | |
|         initSidebar();
 | |
| 
 | |
|         // 3、按钮样式
 | |
|         // 初始化增强的按钮效果
 | |
|         initEnhancedButtonEffects();
 | |
| 
 | |
|         // 简化问题文本动画
 | |
|         simplifyQuestionAnimation();
 | |
|     } else if (win.location.href.indexOf("courseHomeBarrierFree.html") !== -1) {
 | |
|         // 1、导航条切换
 | |
|         initNav();
 | |
| 
 | |
|         // 2、左 侧边栏
 | |
|         initSidebarBarrier();
 | |
|     }
 | |
| 
 | |
| })(window);
 | |
| 
 | |
| // 1、导航条切换
 | |
| function initNav() {
 | |
|     $(".container-header-nav > div").each(function (index) {
 | |
|         $(this).on("click", function () {
 | |
|             $(".container-header-nav > div").removeClass("active");
 | |
|             $(this).addClass("active");
 | |
|             window.open(`./${$(this).data("url")}.html`);
 | |
| 
 | |
|             // console.log("this", this, $(this));
 | |
|             // $(".container-header-nav > div").eq(index).addClass("active");
 | |
|         });
 | |
|     });
 | |
| }
 | |
| 
 | |
| // 2、侧边栏
 | |
| function initSidebar() {
 | |
|     if (
 | |
|         window &&
 | |
|         window.GLOBAL_CONFIG &&
 | |
|         window.GLOBAL_CONFIG.courseList
 | |
|     ) {
 | |
|         // 从路由获取当前课程信息  courseHome.html?id=l01
 | |
|         const id = window.location.search.replace("?id=", "") || "m2x04";
 | |
|         const type = {
 | |
|             l: "live",
 | |
|             c: "language",
 | |
|             m: "math",
 | |
|         }[id[0]];
 | |
|         const courseList = window.GLOBAL_CONFIG.courseList[type];
 | |
| 
 | |
|         const iconList = {
 | |
|             "course": "📺",
 | |
|             "video": "🤼♂️",
 | |
|             "play": "🎮",
 | |
|         };
 | |
| 
 | |
|         // console.log("initSidebar", id, type, courseList);
 | |
| 
 | |
|         $(".container-main-sidebar .directory-list").empty();
 | |
|         let dom = `<ul class="directory-list">`;
 | |
| 
 | |
|         courseList.map((grade, gradeI) => {
 | |
|             grade.map((progress, progressI) => {
 | |
|                 dom = `${dom}
 | |
|                     <li class="grade-item">
 | |
|                         <div class="grade-title">
 | |
|                             <span>${gradeI + 1}年级 <span>${"上下"[progressI]}册</span></span>
 | |
|                             <span class="arrow">▶</span>
 | |
|                         </div>
 | |
|                 `;
 | |
| 
 | |
|                 if (progress) {
 | |
|                     dom = `${dom} <ul class="chapter-list">`;
 | |
| 
 | |
|                     progress.map((chapter, chapterI) => {
 | |
| 
 | |
|                         dom = `${dom}
 | |
|                             <li class="chapter-item">
 | |
|                                 <div class="chapter-title" data-id="${chapter.id}" >
 | |
|                                     <span>第${chapterI + 1}章 ${chapter.name}</span>
 | |
|                                     <span class="arrow">▶</span>
 | |
|                                 </div>
 | |
|                         `;
 | |
| 
 | |
|                         if (chapter.list) {
 | |
|                             dom = `${dom} <ul class="section-list">`;
 | |
| 
 | |
|                             chapter.list.map((section, sectionI) => {
 | |
| 
 | |
|                                 if (sectionI == 0) {
 | |
|                                     dom = `${dom}
 | |
|                                         <div>- 课堂教学 -</div>
 | |
|                                     `;
 | |
|                                 }
 | |
|                                 else if (
 | |
|                                     sectionI > 0 &&
 | |
|                                     chapter.list[sectionI - 1].type == "course" &&
 | |
|                                     section.type == "video"
 | |
|                                 ) {
 | |
|                                     dom = `${dom}
 | |
|                                         <div>- 课堂互动 -</div>
 | |
|                                     `;
 | |
|                                 }
 | |
|                                 else if (
 | |
|                                     sectionI > 0 &&
 | |
|                                     (chapter.list[sectionI - 1].type == "video" || sectionI == 1) &&
 | |
|                                     section.type == "play"
 | |
|                                 ) {
 | |
|                                     dom = `${dom}
 | |
|                                         <div>- 趣味游戏 -</div>
 | |
|                                     `;
 | |
|                                 }
 | |
| 
 | |
|                                 dom = `${dom}
 | |
|                                     <li class="section-item">
 | |
|                                         <div 
 | |
|                                             class="section-title" 
 | |
|                                             onclick="sectionClick(event)"
 | |
|                                             data-info='${JSON.stringify(section)}'
 | |
|                                         > 
 | |
|                                             <span>${iconList[section.type]}</span>
 | |
|                                             ${section.title}
 | |
|                                         </div>
 | |
|                                     </li>
 | |
|                                 `;
 | |
|                             });
 | |
| 
 | |
|                             dom = `${dom} </ul>`;
 | |
|                         };
 | |
| 
 | |
|                         dom = `${dom} </li>`;
 | |
|                     });
 | |
| 
 | |
|                     dom = `${dom} </ul>`;
 | |
|                 }
 | |
| 
 | |
|                 dom = `${dom} </li>`;
 | |
|             })
 | |
|         });
 | |
| 
 | |
|         dom = `${dom} </ul>`;
 | |
|         $(".container-main-sidebar .directory-list").append(dom);
 | |
| 
 | |
|         initSidebarEvent();
 | |
|     }
 | |
| }
 | |
| 
 | |
| // 2、侧边栏 无障碍版本
 | |
| function initSidebarBarrier() {
 | |
|     if (
 | |
|         window &&
 | |
|         window.GLOBAL_CONFIG &&
 | |
|         window.GLOBAL_CONFIG.playList
 | |
|     ) {
 | |
|         let playList = window.GLOBAL_CONFIG.playList;
 | |
| 
 | |
|         const typeName = {
 | |
|             "live": "生活",
 | |
|             "language": "语文",
 | |
|             "math": "数学",
 | |
|         };
 | |
| 
 | |
|         $(".container-main-sidebar .directory-list").empty();
 | |
|         let dom = `<ul class="directory-list">`;
 | |
| 
 | |
|         Object.entries(playList).map((value, valueI) => {
 | |
|             // console.log("initSidebarBarrier", value);
 | |
| 
 | |
|             dom = `${dom}
 | |
|                 <div 
 | |
|                     class="type-item" 
 | |
|                     aria-label="${typeName[value[0]]}课程"
 | |
|                     onmouseenter="debouncedSpeechDomTextBarrier(event)"
 | |
|                     onmouseout="debouncedSpeechDomTextBarrier(event)"
 | |
|                 > 
 | |
|                     - ${typeName[value[0]]} - 
 | |
|                 </div>`;
 | |
| 
 | |
|             value[1].map((play, playI) => {
 | |
|                 dom = `${dom}
 | |
|                     <li class="grade-item">
 | |
|                         <div 
 | |
|                             class="grade-title"
 | |
|                             aria-label="${typeName[value[0]]}课程中的${play.title}游戏"
 | |
|                             onmouseenter="debouncedSpeechDomTextBarrierGame(event)"
 | |
|                             onmouseout="debouncedSpeechDomTextBarrierGame(event)"
 | |
|                             data-info='${JSON.stringify(play)}'
 | |
|                         >
 | |
|                             ${play.title}
 | |
|                         </div>
 | |
|                     </li>
 | |
|                 `;
 | |
|             });
 | |
|         });
 | |
| 
 | |
|         dom = `${dom} </ul>`;
 | |
|         $(".container-main-sidebar .directory-list").append(dom);
 | |
| 
 | |
|         // 年级点击事件
 | |
|         $(".container-main-sidebar .grade-title").click(function (event) {
 | |
| 
 | |
|             // console.log(".container-main-sidebar .grade-title click", this, event);
 | |
| 
 | |
|             if (
 | |
|                 event &&
 | |
|                 event.target &&
 | |
|                 event.target.dataset &&
 | |
|                 event.target.dataset.info
 | |
|             ) {
 | |
|                 const info = JSON.parse(event.target.dataset.info);
 | |
|                 let mainPlay = document.getElementById("mainPlay");
 | |
|                 mainPlay.src = info.url;
 | |
|             }
 | |
| 
 | |
|             // 移除所有active类
 | |
|             $(".container-main-sidebar .grade-title").removeClass("active");
 | |
| 
 | |
|             // 为当前点击的添加active类
 | |
|             $(this).addClass("active");
 | |
| 
 | |
|         });
 | |
|     }
 | |
| }
 | |
| 
 | |
| // 2、侧边栏 事件
 | |
| function initSidebarEvent() {
 | |
|     // 年级点击事件
 | |
|     $(".container-main-sidebar .grade-title").click(function () {
 | |
|         $(this).parent().toggleClass("active");
 | |
|     });
 | |
| 
 | |
|     // 章节点击事件
 | |
|     $(".container-main-sidebar .chapter-title").click(function (e) {
 | |
|         e.stopPropagation(); // 阻止事件冒泡到年级标题
 | |
|         $(this).parent().toggleClass("active");
 | |
|     });
 | |
| 
 | |
|     // 小节点击事件
 | |
|     $(".container-main-sidebar .section-title").click(function (e) {
 | |
|         e.stopPropagation();
 | |
| 
 | |
|         // 移除所有active类
 | |
|         $(".container-main-sidebar .section-title").removeClass("active");
 | |
| 
 | |
|         // 为当前点击的添加active类
 | |
|         $(this).addClass("active");
 | |
|     });
 | |
| 
 | |
|     $(".container-main .sidebar-circle").click(function (e) {
 | |
|         // 是否隐藏了
 | |
|         const isShow = !$(".container-main-sidebar").hasClass("hidden");
 | |
|         // console.log(".sidebar-circle", e, this, isShow);
 | |
|         $(".container-main-sidebar").toggleClass("hidden");
 | |
| 
 | |
|         if (isShow) {
 | |
|             $(".container-main-sidebar").css("width", "0px");
 | |
|             $(this).css("left", "0px");
 | |
|             $(this).text("▶");
 | |
|             $(".container-main-course").css("width", "100%");
 | |
|         } else {
 | |
|             $(".container-main-sidebar").css("width", "var(--sidebar-width)");
 | |
|             $(this).css("left", "var(--sidebar-width)");
 | |
|             $(this).text("◀");
 | |
|             $(".container-main-course").css("width", "calc(100vw - var(--sidebar-width) - 30px)");
 | |
|         }
 | |
|     });
 | |
| }
 | |
| 
 | |
| // 控制功能按钮的展示隐藏 course-operation
 | |
| function showOperationDom() {
 | |
|     $(".course-operation").toggleClass("show");
 | |
| }
 | |
| 
 | |
| // 初始化所有增强的按钮效果
 | |
| function initEnhancedButtonEffects() {
 | |
|     // 首先解除所有现有的事件绑定,避免重复
 | |
|     $('.box-btn-left, .box-btn-right').off();
 | |
| 
 | |
|     // 按钮悬停基本效果
 | |
|     $('.box-btn-left, .box-btn-right').hover(
 | |
|         function () {
 | |
|             const button = $(this);
 | |
| 
 | |
|             // 添加文字缩放动画
 | |
|             button.find('.btn-text').css({
 | |
|                 'animation': 'text-pop 0.8s ease infinite alternate'
 | |
|             });
 | |
| 
 | |
|             // 添加粒子效果
 | |
|             addButtonParticles(button);
 | |
| 
 | |
|             // 添加3D变换效果
 | |
|             button.addClass('btn-hover-active');
 | |
|         },
 | |
|         function () {
 | |
|             const button = $(this);
 | |
| 
 | |
|             // 移除文字动画
 | |
|             button.find('.btn-text').css({
 | |
|                 'animation': 'none'
 | |
|             });
 | |
| 
 | |
|             // 移除粒子
 | |
|             removeButtonParticles();
 | |
| 
 | |
|             // 移除3D效果
 | |
|             button.removeClass('btn-hover-active');
 | |
|         }
 | |
|     );
 | |
| 
 | |
|     // 添加3D移动效果
 | |
|     $('.box-btn-left, .box-btn-right').on('mousemove', function (e) {
 | |
|         const button = $(this);
 | |
| 
 | |
|         // 只有在悬停状态才应用3D效果
 | |
|         if (button.hasClass('btn-hover-active')) {
 | |
|             const buttonRect = button[0].getBoundingClientRect();
 | |
| 
 | |
|             // 计算鼠标在按钮上的相对位置 (-1 到 1 的范围)
 | |
|             const x = ((e.clientX - buttonRect.left) / buttonRect.width) * 2 - 1;
 | |
|             const y = ((e.clientY - buttonRect.top) / buttonRect.height) * 2 - 1;
 | |
| 
 | |
|             // 根据鼠标位置应用3D旋转
 | |
|             button.css({
 | |
|                 'transform': `translateY(-50%) scale(1.15) rotateX(${-y * 15}deg) rotateY(${x * 15}deg)`,
 | |
|                 'transition': 'transform 0.1s ease'
 | |
|             });
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     // 鼠标离开时恢复原始状态
 | |
|     $('.box-btn-left, .box-btn-right').on('mouseleave', function () {
 | |
|         $(this).css({
 | |
|             'transform': 'translateY(-50%)',
 | |
|             'transition': 'transform 0.5s ease'
 | |
|         });
 | |
|     });
 | |
| 
 | |
|     // 添加按钮动画样式
 | |
|     addButtonAnimationStyles();
 | |
| }
 | |
| 
 | |
| // 简化问题文本动画
 | |
| function simplifyQuestionAnimation() {
 | |
|     // DOMSubtreeModified MutationObserver
 | |
|     $('.box-btn-question').on('MutationObserver', function () {
 | |
|         const question = $(this);
 | |
|         const text = question.text().trim();
 | |
| 
 | |
|         if (text.length > 0 && !question.hasClass('animated-question')) {
 | |
|             question.addClass('animated-question');
 | |
|             question.css('opacity', '0');
 | |
| 
 | |
|             setTimeout(function () {
 | |
|                 // 添加有趣的表情符号
 | |
|                 if (!text.includes('🤔')) {
 | |
|                     question.html('🤔 ' + text);
 | |
|                 }
 | |
| 
 | |
|                 question.css({
 | |
|                     'opacity': '1',
 | |
|                     'transform': 'translate(-50%, -65%) scale(1.1)',
 | |
|                     'transition': 'all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275)'
 | |
|                 });
 | |
| 
 | |
|                 setTimeout(function () {
 | |
|                     question.css({
 | |
|                         'transform': 'translate(-50%, -50%) scale(1)',
 | |
|                         'transition': 'all 0.4s ease'
 | |
|                     });
 | |
|                 }, 500);
 | |
|             }, 100);
 | |
|         }
 | |
|     });
 | |
| }
 | |
| 
 | |
| // 添加按钮动画样式
 | |
| function addButtonAnimationStyles() {
 | |
|     // 移除现有的样式元素,避免重复
 | |
|     $('#button-animation-styles').remove();
 | |
| 
 | |
|     // 创建新的样式元素
 | |
|     const styleElement = document.createElement('style');
 | |
|     styleElement.id = 'button-animation-styles';
 | |
|     styleElement.innerHTML = `
 | |
|         @keyframes text-pop {
 | |
|             0% { transform: scale(1); }
 | |
|             100% { transform: scale(1.1); color: #ff6b6b; }
 | |
|         }
 | |
|         
 | |
|         @keyframes shadow-dance {
 | |
|             0% { box-shadow: 0 15px 35px rgba(0, 0, 0, 0.3); }
 | |
|             50% { box-shadow: 0 20px 45px rgba(74, 223, 218, 0.4); }
 | |
|             100% { box-shadow: 0 15px 35px rgba(0, 0, 0, 0.3); }
 | |
|         }
 | |
|         
 | |
|         @keyframes particle-float {
 | |
|             0% { transform: translate(-50%, -50%) translateY(0) rotate(0deg); opacity: 0.7; }
 | |
|             100% { transform: translate(-50%, -50%) translateY(-50px) rotate(360deg); opacity: 0; }
 | |
|         }
 | |
|         
 | |
|         @keyframes sparkle-float {
 | |
|             0% { transform: scale(0); opacity: 0; }
 | |
|             50% { transform: scale(1); opacity: 0.8; }
 | |
|             100% { transform: scale(0); opacity: 0; }
 | |
|         }
 | |
|         
 | |
|         /* 按钮颜色变化动画 */
 | |
|         @keyframes color-shift-left {
 | |
|             0% { background: linear-gradient(145deg, #4adfda, #1bb5ad); }
 | |
|             50% { background: linear-gradient(145deg, #ffa3b7, #ff6b93); }
 | |
|             100% { background: linear-gradient(145deg, #a694ff, #7e64ff); }
 | |
|         }
 | |
|         
 | |
|         @keyframes color-shift-right {
 | |
|             0% { background: linear-gradient(145deg, #9bea72, #5cc332); }
 | |
|             50% { background: linear-gradient(145deg, #ffb347, #ffcc33); }
 | |
|             100% { background: linear-gradient(145deg, #66a6ff, #3d7edb); }
 | |
|         }
 | |
|         
 | |
|         /* 应用颜色变化动画 */
 | |
|         .box-btn-left.btn-hover-active {
 | |
|             animation: border-dance 3s ease infinite, color-shift-left 6s infinite alternate !important;
 | |
|             box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35) !important;
 | |
|         }
 | |
|         
 | |
|         .box-btn-right.btn-hover-active {
 | |
|             animation: border-dance 3s ease infinite, color-shift-right 6s infinite alternate !important;
 | |
|             box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35) !important;
 | |
|         }
 | |
|         
 | |
|         /* 3D文本效果 */
 | |
|         .btn-text {
 | |
|             transition: all 0.3s ease;
 | |
|         }
 | |
|         
 | |
|         .btn-hover-active .btn-text {
 | |
|             text-shadow: 2px 2px 0 #ff6b93, 4px 4px 0 rgba(0, 0, 0, 0.2);
 | |
|             letter-spacing: 1px;
 | |
|         }
 | |
|         
 | |
|         /* 修复冲突 */
 | |
|         .box-btn-left:hover, .box-btn-right:hover {
 | |
|             animation: none !important;
 | |
|         }
 | |
|     `;
 | |
|     document.head.appendChild(styleElement);
 | |
| }
 | |
| 
 | |
| // 添加按钮粒子效果
 | |
| function addButtonParticles(button) {
 | |
|     // 移除已有粒子
 | |
|     removeButtonParticles();
 | |
| 
 | |
|     // 获取按钮位置
 | |
|     const buttonPos = button.offset();
 | |
|     const buttonWidth = button.outerWidth();
 | |
|     const buttonHeight = button.outerHeight();
 | |
| 
 | |
|     // 创建粒子容器
 | |
|     const particleContainer = $('<div class="button-particles"></div>');
 | |
|     particleContainer.css({
 | |
|         'position': 'absolute',
 | |
|         'left': buttonPos.left + 'px',
 | |
|         'top': buttonPos.top + 'px',
 | |
|         'width': buttonWidth + 'px',
 | |
|         'height': buttonHeight + 'px',
 | |
|         'pointer-events': 'none',
 | |
|         'z-index': 1000
 | |
|     });
 | |
| 
 | |
|     // 添加粒子
 | |
|     const colors = ['#ffde59', '#ff914d', '#ff66c4', '#5ce1e6'];
 | |
|     for (let i = 0; i < 12; i++) {
 | |
|         const particle = $('<div class="particle"></div>');
 | |
|         const size = Math.random() * 8 + 4;
 | |
|         const color = colors[Math.floor(Math.random() * colors.length)];
 | |
| 
 | |
|         particle.css({
 | |
|             'position': 'absolute',
 | |
|             'width': size + 'px',
 | |
|             'height': size + 'px',
 | |
|             'background-color': color,
 | |
|             'border-radius': '50%',
 | |
|             'left': (Math.random() * 100) + '%',
 | |
|             'top': (Math.random() * 100) + '%',
 | |
|             'opacity': 0.7,
 | |
|             'animation': `particle-float ${Math.random() * 2 + 1}s ease-out infinite`,
 | |
|             'transform': 'translate(-50%, -50%)'
 | |
|         });
 | |
| 
 | |
|         particleContainer.append(particle);
 | |
|     }
 | |
| 
 | |
|     // 添加闪烁效果
 | |
|     for (let i = 0; i < 5; i++) {
 | |
|         const sparkle = $('<div class="sparkle"></div>');
 | |
|         const size = Math.random() * 6 + 2;
 | |
| 
 | |
|         sparkle.css({
 | |
|             'position': 'absolute',
 | |
|             'width': size + 'px',
 | |
|             'height': size + 'px',
 | |
|             'background-color': '#fff',
 | |
|             'border-radius': '50%',
 | |
|             'left': (Math.random() * 100) + '%',
 | |
|             'top': (Math.random() * 100) + '%',
 | |
|             'box-shadow': '0 0 10px 2px rgba(255, 255, 255, 0.8)',
 | |
|             'opacity': 0.8,
 | |
|             'animation': `sparkle-float ${Math.random() * 1.5 + 0.5}s ease-out infinite`
 | |
|         });
 | |
| 
 | |
|         particleContainer.append(sparkle);
 | |
|     }
 | |
| 
 | |
|     // 添加粒子容器到body
 | |
|     $('body').append(particleContainer);
 | |
| }
 | |
| 
 | |
| // 移除按钮粒子效果
 | |
| function removeButtonParticles() {
 | |
|     $('.button-particles').remove();
 | |
| } |