$(document).ready(function () { var screenwidth = $(window).width() if (screenwidth > 900) { // 定义全局变量 let swiper = null const totalSlides = 4 let currentProgress = 0 let isSlidingEnabled = false let isDragging = false let isPinned = false let progressBarFullHeight = 0 let placeholderInitialized = false let isScrolling = false // 防止滚动冲突 let lastWheelTime = 0 // 记录上次滚轮时间 const WHEEL_THROTTLE_TIME = 16 // 滚轮节流时间 const WHEEL_SPEED_FACTOR = 0.0005 // 更小的滚轮速度因子,让progressHandle移动更慢 const thresholds = { slide2: 0.1667, slide3: 0.5, startSlide: 0.6667, slide4: 0.8333 } // 获取DOM元素 const $swiperContainer = $('#pinElement') const $section2 = $('.setion2') const $section3 = $('.setion4') const $progressContainer = $('.ias-nianbao #progressContainer') const $progressFill = $('.ias-nianbao #progressFill') const $progressHandle = $('.ias-nianbao #progressHandle') const $document = $(document) const $window = $(window) const $htmlBody = $('html, body') // ========== 关键变量:定义进度100%对应的滚动位置 ========== let section2Top = 0 let section3Top = 0 let section3Bottom = 0 // section3出现在视窗底部时的scrollTop let progressEndScrollTop = 0 // 进度条达到100%时的滚动位置 let placeholderTop = 0 // 占位div的顶部位置 // ========== 初始化关键位置信息 ========== function initCriticalPositions() { if (!$section2.length || !$section3.length) return false section2Top = $section2.offset().top section3Top = $section3.offset().top const windowHeight = $window.height() // section3出现在视窗底部时的滚动位置 section3Bottom = section3Top - windowHeight // 进度条达到100%时的滚动位置:就是section3出现在视窗底部的位置 progressEndScrollTop = section3Bottom // 计算占位div需要的高度 progressBarFullHeight = Math.max(0, progressEndScrollTop - section2Top) // 确保有最小高度 if (progressBarFullHeight < windowHeight) { progressBarFullHeight = windowHeight * 2 } // 获取占位div的位置 const $placeholder = $('#pinElementPlaceholder') if ($placeholder.length) { placeholderTop = $placeholder.offset().top } return true } // ========== 创建占位div并设置pinElement为绝对定位 ========== function updatePlaceholderHeight() { if (!$swiperContainer.length) { if (!placeholderInitialized) { setTimeout(updatePlaceholderHeight, 100) } return } if (!initCriticalPositions()) { if (!placeholderInitialized) { setTimeout(updatePlaceholderHeight, 100) } return } const $parent = $swiperContainer.parent() const $placeholder = $('#pinElementPlaceholder') // 创建或更新占位div if (!$placeholder.length) { const $newPlaceholder = $('
', { id: 'pinElementPlaceholder', css: { 'height': progressBarFullHeight + 'px', 'width': '100%', 'visibility': 'hidden', 'pointer-events': 'none' } }) $swiperContainer.before($newPlaceholder) const parentPosition = $parent.css('position') if (parentPosition === 'static') { $parent.css('position', 'relative') } } else { $placeholder.css('height', progressBarFullHeight + 'px') } $swiperContainer.css({ 'position': 'absolute', 'top': '0', 'left': '0', 'width': '100%', 'height': '100%', 'z-index': '7' }) placeholderInitialized = true // 重新获取占位div位置 if ($placeholder.length) { placeholderTop = $placeholder.offset().top } // 重新触发滚动检查 handleScroll() } // 延迟初始化占位div,确保DOM完全加载 setTimeout(() => { updatePlaceholderHeight() }, 300) // ========== 平滑滚动函数 ========== function smoothScrollTo(targetScrollTop) { if (isScrolling) { $htmlBody.stop() } isScrolling = true $htmlBody.animate({ scrollTop: targetScrollTop }, { duration: 150, easing: 'swing', complete: function() { setTimeout(() => { isScrolling = false // 滚动完成后强制检查一次滚动状态 handleScroll() }, 50) } }) } // ========== 核心:根据滚动位置计算进度 ========== function calculateCurrentProgress(scrollTop) { if (!placeholderInitialized || progressBarFullHeight <= 0) return 0 // 重新获取当前位置(可能在resize后变化) if (!initCriticalPositions()) return 0 // 当滚动位置小于section2顶部时,进度为0 if (scrollTop < section2Top) { return 0 } // 当滚动位置超过进度结束位置时,进度为100% if (scrollTop >= progressEndScrollTop) { return 1 } // 正常情况:计算在section2顶部和进度结束位置之间的进度 const progressScroll = scrollTop - section2Top return Math.min(1, progressScroll / progressBarFullHeight) } // ========== 核心:根据进度计算滚动位置 ========== function calculateScrollFromProgress(progress) { if (!placeholderInitialized || progressBarFullHeight <= 0) return 0 // 重新获取当前位置(可能在resize后变化) if (!initCriticalPositions()) return 0 progress = Math.max(0, Math.min(1, progress)) // 当进度为100%时,滚动到进度结束位置 if (progress >= 1) { return progressEndScrollTop } // 正常情况:根据进度计算滚动位置 return section2Top + (progress * progressBarFullHeight) } // ========== 更新pinElement的定位状态 ========== function updatePinElementPosition(scrollTop, isSection3AtBottom) { if (!$swiperContainer.length || !placeholderInitialized) return // 确保占位div位置正确 const $placeholder = $('#pinElementPlaceholder') if ($placeholder.length) { placeholderTop = $placeholder.offset().top } // 当section3出现在页面底部时,停止固定 if (isSection3AtBottom && isPinned) { // 计算绝对定位的top值,使元素保持在当前视觉位置 const absoluteTop = scrollTop - placeholderTop $swiperContainer.css({ 'position': 'absolute', 'top': `${absoluteTop}px`, 'left': '0', 'width': '100%', 'z-index': '7' }) isPinned = false $swiperContainer.removeClass('pinned') return } // 当滚动到section2顶部,且section3未出现在底部时,开始固定 if (scrollTop >= section2Top && !isPinned && !isSection3AtBottom) { $swiperContainer.css({ 'position': 'fixed', 'top': '0', 'left': '0', 'width': '100%', 'z-index': '1000' }) isPinned = true $swiperContainer.addClass('pinned') } else if (scrollTop < section2Top && isPinned) { // 切换回绝对定位(滚动到section2上方时) const absoluteTop = Math.max(0, section2Top - placeholderTop) $swiperContainer.css({ 'position': 'absolute', 'top': `${absoluteTop}px`, 'left': '0', 'width': '100%', 'z-index': '7' }) isPinned = false $swiperContainer.removeClass('pinned') } // 如果不是固定状态,需要实时更新绝对定位的top值 if (!isPinned && !isSection3AtBottom && scrollTop >= section2Top) { const absoluteTop = scrollTop - placeholderTop $swiperContainer.css({ 'position': 'absolute', 'top': `${absoluteTop}px` }) } } // ========== 滚动监听函数 ========== function handleScroll() { // 如果在滚动动画中或正在拖拽,不处理滚动事件 if (isScrolling || isDragging || !placeholderInitialized) return if (!$swiperContainer.length || !$section2.length || !$section3.length) return const scrollTop = $window.scrollTop() const windowHeight = $window.height() // 重新获取关键位置 if (!initCriticalPositions()) return // 计算section3是否出现在页面底部 const isSection3AtBottom = scrollTop + windowHeight >= section3Top // 更新进度条 const newProgress = calculateCurrentProgress(scrollTop) if (Math.abs(newProgress - currentProgress) > 0.001) { currentProgress = newProgress updateProgressDisplay(currentProgress) updateSlideVisibilityByProgress(currentProgress) } // 更新pinElement的定位状态 updatePinElementPosition(scrollTop, isSection3AtBottom) } $window.on('scroll', function() { if (!isDragging) { handleScroll() } }) // 初始检查一次 setTimeout(() => { handleScroll() }, 500) // ========== 初始化Swiper ========== swiper = new Swiper(".ias-nianbao .mySwiper", { slidesPerView: 2.5, spaceBetween: 30, allowTouchMove: false, draggable: false, mousewheel: false, simulateTouch: false, grabCursor: false, observer: true, observeParents: true, speed: 600, on: { init: function () { createProgressTicks() updateProgressDisplay(0) initializeSlideVisibility() } } }) // ========== 进度条相关函数 ========== function createProgressTicks() { $progressContainer.find('.progress-tick, .progress-label').remove() for (let i = 0; i < totalSlides; i++) { const tickPosition = (i / (totalSlides - 1)) * 100 $('
') .addClass('progress-tick') .css('left', `${tickPosition}%`) .appendTo($progressContainer) const labelText = getSlideLabel(i + 1) $('
') .addClass('progress-label progress-label' + i) .text(labelText) .css('left', `${tickPosition}%`) .appendTo($progressContainer) } } function getSlideLabel(slideNumber) { const labels = { 1: "步骤 01", 2: "步骤 02", 3: "步骤 03", 4: "步骤 04" } return labels[slideNumber] || `Slide ${slideNumber}` } function initializeSlideVisibility() { if (swiper && swiper.slides && swiper.slides.length > 0) { for (let i = 0; i < swiper.slides.length; i++) { const slide = swiper.slides[i] const $slide = $(slide) $slide.toggleClass('visible', i === 0) } } } function updateProgressDisplay(progress) { progress = Math.max(0, Math.min(1, progress)) const progressPercent = progress * 100 $progressFill.css('width', `${progressPercent}%`) $progressHandle.css('left', `${progressPercent}%`) const isAtBottom = progress >= 0.99 const isAtTop = progress <= 0.01 if (isAtBottom || isAtTop) { $progressHandle.addClass('at-boundary') } else { $progressHandle.removeClass('at-boundary') } } function updateSlideVisibilityByProgress(progress) { if (!swiper) return if (swiper.slides && swiper.slides.length > 0) { $(swiper.slides[0]).addClass('visible') $(swiper.slides[1]).toggleClass('visible', progress >= thresholds.slide2) $(swiper.slides[2]).toggleClass('visible', progress >= thresholds.slide3) $(swiper.slides[3]).toggleClass('visible', progress >= thresholds.slide4) } if (progress >= thresholds.startSlide) { if (!isSlidingEnabled) { isSlidingEnabled = true setTimeout(() => { swiper.slideTo(1, 800) }, 150) } else { let targetSlide = 1 if (progress >= thresholds.slide4) targetSlide = 2 if (progress >= 0.95) targetSlide = 3 swiper.slideTo(targetSlide, 600, false) } } else { if (isSlidingEnabled) { isSlidingEnabled = false swiper.slideTo(0, 800) } else if (swiper.activeIndex !== 0) { swiper.slideTo(0, 0, false) } } } // ========== 修复的滚轮处理函数 - 更小的增量 ========== function handleWheelOnElement(e, isInPinElementArea) { // 如果正在拖拽或滚动,直接返回允许默认行为 if (isDragging || isScrolling) return true // 如果占位div还没初始化,允许默认滚动 if (!placeholderInitialized || progressBarFullHeight <= 0) return true // ========== 关键修改:如果鼠标在pinElement区域但pinElement没有固定,允许默认滚动 ========== if (isInPinElementArea && !isPinned) { return true // 允许默认滚动行为 } const now = Date.now() // 节流处理:防止滚轮事件过于频繁 if (now - lastWheelTime < WHEEL_THROTTLE_TIME) { return false // 忽略过于频繁的事件 } lastWheelTime = now // 获取滚轮delta值 const deltaY = e.originalEvent.deltaY // 计算滚动方向 const isScrollingDown = deltaY > 0 // 获取当前滚动位置 const scrollTop = $window.scrollTop() // 检查边界条件 // 如果正在向上滚动且已经在section2顶部之前,允许默认滚动 if (!isScrollingDown && scrollTop <= section2Top) { return true } // 如果正在向下滚动且已经到达进度结束位置,允许默认滚动 if (isScrollingDown && scrollTop >= progressEndScrollTop) { return true } // 计算滚轮delta对应的滚动距离 - 使用更小的因子 // WHEEL_SPEED_FACTOR = 0.0005 比之前的0.002小4倍 const scrollDelta = deltaY * WHEEL_SPEED_FACTOR * progressBarFullHeight // 计算目标滚动位置 let targetScroll = scrollTop + scrollDelta // 限制目标滚动位置在有效范围内 if (targetScroll < section2Top) { // 如果向上滚动到section2之前,允许默认滚动 if (currentProgress <= 0.01) { return true } targetScroll = section2Top } else if (targetScroll > progressEndScrollTop) { targetScroll = progressEndScrollTop } // 计算新进度 const newProgress = calculateCurrentProgress(targetScroll) // 更新进度 if (Math.abs(newProgress - currentProgress) > 0.001) { currentProgress = newProgress updateProgressDisplay(currentProgress) updateSlideVisibilityByProgress(currentProgress) } // 直接设置滚动位置 $window.scrollTop(targetScroll) // 立即更新pinElement位置 const windowHeight = $window.height() const isSection3AtBottom = targetScroll + windowHeight >= section3Top updatePinElementPosition(targetScroll, isSection3AtBottom) // 阻止默认滚轮行为 return false } // ========== 事件监听 ========== // 点击进度条跳转 function handleProgressClick(e) { if (isDragging || isScrolling) return // 如果占位div还没初始化,不处理 if (!placeholderInitialized || progressBarFullHeight <= 0) return // 检查是否点击了手柄区域 const $target = $(e.target) if ($target.is('#progressHandle') || $target.closest('#progressHandle').length > 0) { return } // 获取点击位置 const rect = $progressContainer[0].getBoundingClientRect() const clickX = e.clientX - rect.left const containerWidth = rect.width // 计算点击的进度位置 const newProgress = Math.max(0, Math.min(1, clickX / containerWidth)) // 直接更新进度 currentProgress = newProgress updateProgressDisplay(currentProgress) updateSlideVisibilityByProgress(currentProgress) // 跳转到对应位置 const targetScroll = calculateScrollFromProgress(currentProgress) // 在滚动前先检查并更新pinElement状态 const windowHeight = $window.height() const isSection3AtBottom = targetScroll + windowHeight >= section3Top // 如果目标位置在section2和section3之间,应该固定 if (targetScroll >= section2Top && !isSection3AtBottom && !isPinned) { $swiperContainer.css({ 'position': 'fixed', 'top': '0', 'left': '0', 'width': '100%', 'z-index': '1000' }) isPinned = true $swiperContainer.addClass('pinned') } smoothScrollTo(targetScroll) } // 绑定点击事件 $progressContainer.on('click', handleProgressClick) $progressFill.on('click', handleProgressClick) // ========== 拖拽进度条手柄 ========== $progressHandle.on('mousedown', function (e) { e.preventDefault() e.stopPropagation() // 如果占位div还没初始化,不处理 if (!placeholderInitialized || progressBarFullHeight <= 0) return isDragging = true // 添加拖拽状态类 $progressHandle.addClass('dragging') $progressContainer.addClass('dragging-active') $(".ias-tpl-header").hide(); // 获取初始值 const containerRect = $progressContainer[0].getBoundingClientRect() const containerWidth = containerRect.width const startX = e.clientX const startProgress = currentProgress // 关键修复:监听整个document的mousemove,而不是限制在进度条区域 function onHandleDrag(moveEvent) { moveEvent.preventDefault() // 计算鼠标位置 const currentX = moveEvent.clientX const deltaX = currentX - startX // 计算进度变化 const deltaProgress = deltaX / containerWidth const newProgress = Math.max(0, Math.min(1, startProgress + deltaProgress)) // 更新进度 if (Math.abs(newProgress - currentProgress) > 0.0001) { currentProgress = newProgress // 只更新left样式 const progressPercent = currentProgress * 100 $progressHandle.css('left', `${progressPercent}%`) $progressFill.css('width', `${progressPercent}%`) // 更新swiper可见性 updateSlideVisibilityByProgress(currentProgress) // 计算目标滚动位置 const targetScroll = calculateScrollFromProgress(currentProgress) // 直接设置滚动位置 $window.scrollTop(targetScroll) // 立即更新pinElement位置 const windowHeight = $window.height() const isSection3AtBottom = targetScroll + windowHeight >= section3Top updatePinElementPosition(targetScroll, isSection3AtBottom) } } // 拖拽结束函数 function stopHandleDrag() { $(".ias-tpl-header").show(); // 移除事件监听器 $document .off('mousemove', onHandleDrag) .off('mouseup', stopHandleDrag) // 移除拖拽状态类 $progressHandle.removeClass('dragging') $progressContainer.removeClass('dragging-active') // 确保最终位置正确 const finalScrollTop = $window.scrollTop() const finalProgress = calculateCurrentProgress(finalScrollTop) if (Math.abs(finalProgress - currentProgress) > 0.01) { currentProgress = finalProgress updateProgressDisplay(currentProgress) updateSlideVisibilityByProgress(currentProgress) } // 重置状态 isDragging = false // 拖拽结束后强制检查一次 setTimeout(() => { handleScroll() }, 50) } // 绑定事件监听器到整个document,这样即使鼠标离开进度条区域也能继续拖拽 $document .on('mousemove', onHandleDrag) .on('mouseup', stopHandleDrag) // 防止选中文本 $document.on('selectstart', function(e) { e.preventDefault() return false }) // 防止拖拽时触发其他事件 return false }) // 绑定滚轮事件到pinElement区域 $swiperContainer.on('wheel', function(e) { // 处理滚轮事件,传入true表示在pinElement区域 const allowDefault = handleWheelOnElement(e, true) if (!allowDefault) { e.preventDefault() e.stopPropagation() } return allowDefault }) // 绑定滚轮事件到进度条区域 - 注意:进度条区域不受限制 $progressContainer.on('wheel', function(e) { // 处理滚轮事件,传入false表示在进度条区域(进度条区域总是可以控制) const allowDefault = handleWheelOnElement(e, false) if (!allowDefault) { e.preventDefault() e.stopPropagation() } return allowDefault }) // 初始更新 setTimeout(() => { if (swiper && swiper.initialized) { createProgressTicks() updateProgressDisplay(0) } }, 300) // 窗口大小变化时更新 let resizeTimeout $window.on('resize', function () { clearTimeout(resizeTimeout) resizeTimeout = setTimeout(() => { // 重新初始化关键位置 initCriticalPositions() createProgressTicks() updateProgressDisplay(currentProgress) // 更新占位div的高度 updatePlaceholderHeight() // 重新触发滚动检查 if (!isDragging) { handleScroll() } }, 200) }) } else { // 移动端代码保持不变 var mySwiper = new Swiper('.mySwiper', { loop: false, pagination: { el: '#progressContainer', clickable: true, renderBullet: function (index, className) { let text = '' switch (index) { case 0: text = '步骤 01'; break case 1: text = '步骤 02'; break case 2: text = '步骤 03'; break case 3: text = '步骤 04'; break } return `${text}` }, }, navigation: { nextEl: '.swiper-button-next01', prevEl: '.swiper-button-prev01', }, slidesPerView: 1, speed: 500, autoplay: false, spaceBetween: 14, keyboard: true, observer: true, observeParents: true, on: { transitionStart: function (mySwiper) { $('.mySwiper').find('img').trigger('appear') }, slideChangeTransitionEnd: function () { gatabswiper(this) }, }, }) } }) $(function () { var screenwidth = $(window).width() // WebP支持检测(首次运行时缓存结果) function checkWebPSupport(callback) { if ( typeof localStorage !== "undefined" && localStorage.getItem("webpSupport") !== null ) { return callback(localStorage.getItem("webpSupport") === "true") } const img = new Image() img.onload = function () { const result = img.width > 0 && img.height > 0 localStorage.setItem("webpSupport", result) callback(result) } img.onerror = function () { localStorage.setItem("webpSupport", false) callback(false) } img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" } checkWebPSupport(function (isSupported) { $("img").each(function () { const $img = $(this) const webpSrc = $img .closest("picture") .find('source[type="image/webp"]') .data("srcset") const fallbackSrc = $img.data("src") // 动态设置真实图片路径 $img.data("original", isSupported ? webpSrc : fallbackSrc) }) $("img").lazyload({ threshold: 200, effect: "fadeIn", appear: function () { const realSrc = $(this).data("original") $(this).attr("src", realSrc) $(this).addClass("lazy-loaded") }, load: function () { $(this).addClass("lazy-loaded") }, error: function () { $(this).attr("src", "img/error.jpg") }, }) }) // 初始化懒加载 $("img").lazyload({ effect: "fadeIn", // 淡入效果 threshold: 100, // 提前300px加载 failure_limit: 15, // 最大容错数量 skip_invisible: true, // 加载隐藏图片 appear: function () { // 加载前回调 $(this).css("background", "transparent") $(this).removeClass("lazyload") }, load: function () { // 加载完成回调 $(this).addClass("lazy-loaded") }, }) // 20260202 // 轮播一 var mySwiper = new Swiper('.as-tpl-hm-banner01', { loop: false, pagination: { el: '.swiper-pagination01', clickable: true, renderBullet: function (index, className) { switch (index) { case 0: text = '步骤 01' break case 1: text = '步骤 02' break case 2: text = '步骤 03' break } return ( '' + text + '' ) }, }, navigation: { nextEl: '.swiper-button-next01', prevEl: '.swiper-button-prev01', }, slidesPerView: 1, speed: 500, autoplay: false, spaceBetween: 14, keyboard: true, observer: true, observeParents: true, breakpoints: { 900: { // PC端 loop: false, slidesPerView: 3, spaceBetween: 18, keyboard: true, observer: true, observeParents: true, // slideToClickedSlide: true, }, }, on: { transitionStart: function (mySwiper) { }, slideChangeTransitionEnd: function () { $('.as-tpl-hm-banner01').find('img').trigger('appear') gatabswiper(this) }, }, }) if (screenwidth < 900) { setTimeout(function () { $('.ias-tpl-hmpc-show ').remove() }, 50) // 华为乾崑app $(document).on('click', '.ias-car-section06 .section06-con .wechat-con li h4', function (e) { e.stopPropagation() if ($(this).hasClass('active')) { $(this).removeClass('active') $(this).next('.mob-wechat-pop').hide() } else { $(this).addClass('active') $(this).next('.mob-wechat-pop').show() $(this).parent('li').siblings().find('.mob-wechat-pop').hide() $(this).parent('li').siblings().find('h4').removeClass('active') } }) $(document).on('click', '.mob-wechat-pop', function (e) { e.stopPropagation() $(this).show() }) $(document).on('click', function () { $('.mob-wechat-pop').hide() $('.ias-car-section06 .section06-con .wechat-con li h4').removeClass('active') }) var kv_vd01 = $('.slide-ab01').data('url') $('.slide-ab01').find('video').attr('src', kv_vd01) // $('.slide-ab01').find('video')[0].play() } else { $('.ias-tpl-hmmob-show ').remove() var vd01 = $('.vd01').data('url') $('.vd01').find('video').attr('src', vd01) } $(".setion5_desc .tit").click(function(){ var _this = $(this) _this.parent().toggleClass('active').siblings().removeClass('active'); _this.next().slideToggle(); _this.parent().siblings().find('.txt').slideUp(); if(screenwidth < 900){ $(".ias-mobile-tpl-header").hide(); setTimeout(function(){ $('html, body').animate({ scrollTop: _this.parent().offset().top - 150 }, 500); setTimeout(function(){ $(".ias-mobile-tpl-header").show(); },500) },500) } }) $(".setion5_desc .all.all1").click(function(){ $(".setion5_desc").addClass('active'); for(let i=0;i<$(".setion5_desc .list").length;i++){ $(".setion5_desc .list").eq(i).addClass('active'); $(".setion5_desc .list").eq(i).find('.txt').slideDown(); } }) $(".setion5_desc .all.all2").click(function(){ $(".setion5_desc").removeClass('active'); for(let i=0;i<$(".setion5_desc .list").length;i++){ $(".setion5_desc .list").eq(i).removeClass('active'); $(".setion5_desc .list").eq(i).find('.txt').slideUp(); } }) }) document.addEventListener('DOMContentLoaded', function() { var video = document.getElementById('myVideo'); // 微信环境检测 function isWeixin() { return /MicroMessenger/i.test(navigator.userAgent); } if (isWeixin()) { // 微信环境下使用WeixinJSBridge if (typeof WeixinJSBridge != "undefined") { WeixinJSBridge.invoke('getNetworkType', {}, function() { video.play(); }); } else { document.addEventListener('WeixinJSBridgeReady', function() { WeixinJSBridge.invoke('getNetworkType', {}, function() { video.play(); }); }, false); } } else { // 非微信环境正常播放 video.play().catch(function(e) { console.log("Autoplay prevented:", e); }); } });