你想要理解 Bizland 模板中这段核心 JavaScript 代码的功能和逻辑,我会按功能模块拆解,用通俗易懂的语言讲解每个部分的作用、执行逻辑和实际效果,让你清楚每一段代码在页面中扮演的角色。

整体说明

这段代码是一个自执行匿名函数(function() { ... })();),包裹所有逻辑的目的是:

  • 开启严格模式("use strict"),避免语法错误和意外行为;
  • 隔离变量作用域,防止全局变量污染;
  • 所有功能都是针对 Bizland 模板的交互效果(导航、滚动、动画、加载等),依赖 Bootstrap 5 基础,但补充了模板专属的交互逻辑。

模块 1:页面滚动时给 body 添加/移除 .scrolled 类

function toggleScrolled() {
  const selectBody = document.querySelector('body');
  const selectHeader = document.querySelector('#header');
  // 仅当头部有指定固定类时才执行(避免无固定导航时无效操作)
  if (!selectHeader.classList.contains('scroll-up-sticky') && !selectHeader.classList.contains('sticky-top') && !selectHeader.classList.contains('fixed-top')) return;
  // 滚动超过100px → 加.scrolled类;否则移除
  window.scrollY > 100 ? selectBody.classList.add('scrolled') : selectBody.classList.remove('scrolled');
}
// 监听滚动和页面加载事件,触发函数
document.addEventListener('scroll', toggleScrolled);
window.addEventListener('load', toggleScrolled);

作用:

  • 页面滚动超过 100px 时,给 <body>.scrolled 类,用于修改导航栏样式(比如导航栏背景变实、高度变小、阴影出现);
  • 滚动回到顶部时移除该类,恢复导航栏初始样式;
  • 先判断头部是否有固定类(sticky-top/fixed-top),避免无固定导航时执行无效逻辑。

模块 2:移动端导航栏切换(汉堡菜单)

const mobileNavToggleBtn = document.querySelector('.mobile-nav-toggle');

function mobileNavToogle() {
  document.querySelector('body').classList.toggle('mobile-nav-active'); // 控制导航显示/隐藏
  mobileNavToggleBtn.classList.toggle('bi-list'); // 切换图标:列表 → 关闭
  mobileNavToggleBtn.classList.toggle('bi-x');
}
// 点击汉堡按钮触发切换
if (mobileNavToggleBtn) {
  mobileNavToggleBtn.addEventListener('click', mobileNavToogle);
}

作用:

  • 移动端点击汉堡菜单按钮时,切换 <body>.mobile-nav-active 类(控制侧边导航栏显示/隐藏);
  • 同时切换按钮图标:从「三条杠(bi-list)」变成「叉号(bi-x)」,给用户视觉反馈。

模块 3:移动端点击锚点链接后关闭导航

document.querySelectorAll('#navmenu a').forEach(navmenu => {
  navmenu.addEventListener('click', () => {
    if (document.querySelector('.mobile-nav-active')) {
      mobileNavToogle(); // 关闭移动端导航
    }
  });
});

作用:

  • 移动端点击导航栏的锚点链接(比如「About」「Services」)后,自动关闭侧边导航栏,提升用户体验;
  • 避免用户点击链接后导航栏仍遮挡页面内容。

模块 4:移动端导航下拉菜单切换

document.querySelectorAll('.navmenu .toggle-dropdown').forEach(navmenu => {
  navmenu.addEventListener('click', function(e) {
    e.preventDefault(); // 阻止默认链接行为
    this.parentNode.classList.toggle('active'); // 父元素加active类
    this.parentNode.nextElementSibling.classList.toggle('dropdown-active'); // 下拉菜单显示/隐藏
    e.stopImmediatePropagation(); // 阻止事件冒泡(避免触发其他点击逻辑)
  });
});

作用:

  • 移动端点击导航栏的下拉菜单按钮(比如「Services ▼」)时,展开/收起下拉子菜单;
  • e.stopImmediatePropagation() 防止点击下拉按钮时触发「关闭导航」的逻辑(模块3)。

模块 5:预加载动画移除

const preloader = document.querySelector('#preloader');
if (preloader) {
  window.addEventListener('load', () => {
    preloader.remove(); // 页面加载完成后移除预加载动画
  });
}

作用:

  • 页面完全加载后,移除 <div id="preloader"> 元素,关闭加载动画;
  • 避免预加载层一直遮挡页面内容。

模块 6:回到顶部按钮控制

let scrollTop = document.querySelector('.scroll-top');

function toggleScrollTop() {
  if (scrollTop) {
    // 滚动超过100px → 显示回到顶部按钮;否则隐藏
    window.scrollY > 100 ? scrollTop.classList.add('active') : scrollTop.classList.remove('active');
  }
}
// 点击回到顶部按钮 → 平滑滚动到顶部
scrollTop.addEventListener('click', (e) => {
  e.preventDefault();
  window.scrollTo({
    top: 0,
    behavior: 'smooth' // 平滑滚动(而非瞬间跳转)
  });
});
// 监听加载和滚动事件
window.addEventListener('load', toggleScrollTop);
document.addEventListener('scroll', toggleScrollTop);

作用:

  • 页面滚动超过 100px 时,显示「回到顶部」按钮(加 .active 类);
  • 点击按钮时,页面平滑滚动到顶部(behavior: 'smooth'),提升体验;
  • 滚动回顶部后,隐藏按钮。

模块 7:AOS 滚动动画初始化

function aosInit() {
  AOS.init({
    duration: 600, // 动画持续时间600ms
    easing: 'ease-in-out', // 动画缓动效果
    once: true, // 只执行一次动画(滚动回来不再重复)
    mirror: false // 滚动离开时不反向动画
  });
}
window.addEventListener('load', aosInit);

作用:

  • 初始化 AOS(Animate On Scroll)库,实现「元素滚动到可视区域时触发动画」的效果;
  • 比如 Bizland 模板中「About」「Services」区块的渐入、滑入动画,都是由 AOS 实现;
  • 配置 once: true 避免动画重复触发(比如滚动上去又下来,元素不会重复动画)。

模块 8:GLightbox 图片灯箱初始化

const glightbox = GLightbox({
  selector: '.glightbox' // 选择所有带.glighbox类的元素
});

作用:

  • 初始化 GLightbox 库,实现图片/视频的灯箱效果(点击图片弹出全屏预览);
  • 比如模板中「Portfolio」区块的图片,点击后会以灯箱形式放大显示。

模块 9:技能进度条动画(滚动到可视区域时触发)

let skillsAnimation = document.querySelectorAll('.skills-animation');
skillsAnimation.forEach((item) => {
  new Waypoint({ // 依赖 Waypoint 库,监听元素是否进入可视区域
    element: item,
    offset: '80%', // 元素进入可视区域80%时触发
    handler: function(direction) {
      let progress = item.querySelectorAll('.progress .progress-bar');
      progress.forEach(el => {
        // 进度条宽度设置为aria-valuenow的值(比如90%)
        el.style.width = el.getAttribute('aria-valuenow') + '%';
      });
    }
  });
});

作用:

  • 滚动到「Skills」区块时,进度条从 0 动画到指定百分比(比如「HTML 90%」);
  • offset: '80%' 表示元素距离顶部还有 20% 时就触发动画,避免用户看到进度条「静止不动」;
  • 依赖 Waypoint 库实现「滚动监听」。

模块 10:PureCounter 数字计数动画初始化

new PureCounter();

作用:

  • 初始化 PureCounter 库,实现「数字从 0 计数到目标值」的动画;
  • 比如 Bizland 模板中「100+ Projects」「50+ Clients」这类数字统计区块,滚动到可视区域时自动计数。

模块 11:Swiper 轮播图初始化

function initSwiper() {
  document.querySelectorAll(".init-swiper").forEach(function(swiperElement) {
    // 从.swiper-config中读取轮播配置(JSON格式)
    let config = JSON.parse(
      swiperElement.querySelector(".swiper-config").innerHTML.trim()
    );

    if (swiperElement.classList.contains("swiper-tab")) {
      initSwiperWithCustomPagination(swiperElement, config); // 自定义分页的轮播
    } else {
      new Swiper(swiperElement, config); // 普通轮播初始化
    }
  });
}
window.addEventListener("load", initSwiper);

作用:

  • 初始化 Swiper 轮播库,支持模板中的轮播组件(比如「Testimonials」「Portfolio」轮播);
  • 配置从 HTML 中的 .swiper-config 标签读取(JSON 格式),实现「不同轮播不同配置」;
  • 支持自定义分页的轮播(swiper-tab 类)。

模块 12:Isotope 瀑布流/筛选布局初始化

document.querySelectorAll('.isotope-layout').forEach(function(isotopeItem) {
  let layout = isotopeItem.getAttribute('data-layout') ?? 'masonry'; // 默认瀑布流布局
  let filter = isotopeItem.getAttribute('data-default-filter') ?? '*'; // 默认显示所有
  let sort = isotopeItem.getAttribute('data-sort') ?? 'original-order'; // 默认排序

  let initIsotope;
  // 等待图片加载完成后初始化(避免布局错乱)
  imagesLoaded(isotopeItem.querySelector('.isotope-container'), function() {
    initIsotope = new Isotope(isotopeItem.querySelector('.isotope-container'), {
      itemSelector: '.isotope-item', // 筛选的子元素类名
      layoutMode: layout, // 布局模式(瀑布流/网格)
      filter: filter, // 默认筛选条件
      sortBy: sort // 排序方式
    });
  });

  // 筛选按钮点击事件
  isotopeItem.querySelectorAll('.isotope-filters li').forEach(function(filters) {
    filters.addEventListener('click', function() {
      // 切换筛选按钮的active类
      isotopeItem.querySelector('.isotope-filters .filter-active').classList.remove('filter-active');
      this.classList.add('filter-active');
      // 重新排列元素(按筛选条件)
      initIsotope.arrange({
        filter: this.getAttribute('data-filter')
      });
      if (typeof aosInit === 'function') {
        aosInit(); // 重新初始化AOS动画(避免筛选后动画失效)
      }
    }, false);
  });
});

作用:

  • 初始化 Isotope 库,实现「Portfolio」区块的瀑布流布局和筛选功能(比如按「All」「Web Design」「App Design」筛选);
  • imagesLoaded 确保图片加载完成后再初始化,避免布局错位;
  • 点击筛选按钮时,动态过滤显示的项目,并重新触发 AOS 动画。

模块 13:FAQ 折叠面板切换

document.querySelectorAll('.faq-item h3, .faq-item .faq-toggle').forEach((faqItem) => {
  faqItem.addEventListener('click', () => {
    faqItem.parentNode.classList.toggle('faq-active'); // 展开/收起FAQ项
  });
});

作用:

  • 点击 FAQ 项的标题或切换按钮时,展开/收起对应的回答内容;
  • 给父元素加 .faq-active 类,通过 CSS 控制回答内容的显示/隐藏。

模块 14:锚点链接滚动位置修正

window.addEventListener('load', function(e) {
  if (window.location.hash) { // 页面URL包含锚点(比如#about)
    if (document.querySelector(window.location.hash)) {
      setTimeout(() => {
        let section = document.querySelector(window.location.hash);
        // 获取section的scrollMarginTop(避免导航栏遮挡)
        let scrollMarginTop = getComputedStyle(section).scrollMarginTop;
        window.scrollTo({
          top: section.offsetTop - parseInt(scrollMarginTop),
          behavior: 'smooth'
        });
      }, 100); // 延迟100ms执行,确保页面元素加载完成
    }
  }
});

作用:

  • 页面加载时如果 URL 包含锚点(比如 https://xxx.com/#about),修正滚动位置;
  • 减去 scrollMarginTop 避免固定导航栏遮挡锚点区域(比如「About」区块被导航栏盖住);
  • 延迟 100ms 执行,确保页面元素完全加载后再计算位置。

模块 15:导航栏锚点高亮(Scrollspy)

let navmenulinks = document.querySelectorAll('.navmenu a');

function navmenuScrollspy() {
  navmenulinks.forEach(navmenulink => {
    if (!navmenulink.hash) return; // 非锚点链接跳过
    let section = document.querySelector(navmenulink.hash);
    if (!section) return; // 锚点对应元素不存在跳过
    let position = window.scrollY + 200; // 滚动位置+200px(提前高亮)
    // 滚动到对应区块时,给链接加active类;否则移除
    if (position >= section.offsetTop && position <= (section.offsetTop + section.offsetHeight)) {
      document.querySelectorAll('.navmenu a.active').forEach(link => link.classList.remove('active'));
      navmenulink.classList.add('active');
    } else {
      navmenulink.classList.remove('active');
    }
  })
}
// 监听加载和滚动事件
window.addEventListener('load', navmenuScrollspy);
document.addEventListener('scroll', navmenuScrollspy);

作用:

  • 模拟 Bootstrap Scrollspy 功能:滚动到某个区块时,导航栏对应的链接自动高亮(加 .active 类);
  • position = window.scrollY + 200 实现「提前高亮」,提升用户体验(比如滚动到 About 区块上方 200px 时,About 链接就高亮)。

总结

核心功能分类:

  1. 导航交互:移动端导航切换、下拉菜单、锚点高亮、滚动时导航样式变化;
  2. 滚动相关:回到顶部按钮、AOS 滚动动画、技能进度条、数字计数动画;
  3. 视觉交互:预加载移除、灯箱效果、轮播图、FAQ 折叠、瀑布流筛选;
  4. 体验优化:锚点滚动位置修正、移动端点击链接关闭导航。

关键依赖库:

  • AOS:滚动动画;
  • GLightbox:图片灯箱;
  • Waypoint:滚动监听;
  • PureCounter:数字计数;
  • Swiper:轮播图;
  • Isotope:瀑布流/筛选;
  • imagesLoaded:图片加载监听。

这段代码的核心是基于 Bootstrap 5 补充模板专属的交互逻辑,所有功能都是为了让 Bizland 模板的交互更流畅、视觉效果更丰富,同时适配移动端和桌面端的不同体验。(豆包)

标签: none