mcpField
B
barba-js

barba-js

github.com/freshtechbro设计与 UI1.2k2.4k 次安装49 周前更新
代码仓库

关于 barba-js

barba-js 是一项介绍 Barba.js 页面过渡的技能,面向构建多页网站的开发者。内容涵盖生命周期钩子、页面专属逻辑、路由和动画模式,让网站实现类似 SPA 的导航体验。

主要功能

  1. 01通过 AJAX 导航且无需整页刷新
  2. 02用于控制过渡的生命周期钩子
  3. 03基于命名空间的页面专属逻辑
  4. 04条件式与路由式过渡
  5. 05GSAP 动画模式
  6. 06项目设置工具与起始模板

适用场景

  1. 01为多页网站添加动画过渡
  2. 02在导航后运行页面专属初始化
  3. 03根据导航起点或终点选择过渡
  4. 04生成 Barba.js 设置与过渡样板代码

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/freshtechbro/claudedesignskills --skill barba-js

安装后在 Claude Code 中输入/barba-js确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
README.md
references/
api_reference.md
gsap_integration.md
hooks_guide.md
transition_patterns.md
scripts/
project_setup.py
transition_generator.py

详细介绍

Barba.js

用于在网站页面之间创建流畅过渡的现代页面过渡库。Barba.js 通过接管导航并在不完整重新加载页面的情况下管理过渡,让多页面网站拥有类似单页应用(SPA)的体验。

概览

Barba.js 是一个轻量级(压缩后仅 7kb)的 JavaScript 库,可拦截页面间的导航,通过 AJAX 获取新内容,并在旧容器与新容器之间实现平滑过渡。它能减少页面加载延迟和 HTTP 请求,同时保留传统多页面架构的优势。

核心功能:

  • 无需完整重新加载页面即可实现平滑过渡
  • 提供生命周期钩子,精确控制过渡阶段
  • 基于视图的逻辑,用于处理页面专属行为
  • 内置路由功能,由 @barba/router 插件提供
  • 可扩展的插件系统
  • 体积小巧,性能出色
  • 与框架无关(可与原生 JS、GSAP、anime.js 等配合使用)

核心概念

1. Wrapper、Container 和 Namespace

Barba.js 使用特定的 DOM 结构来管理过渡:

HTML 结构:

<body data-barba="wrapper">
  
  <header>
    <nav>
      <a href="/">Home</a>
      <a href="/about">About</a>
    </nav>
  </header>

  
  <main data-barba="container" data-barba-namespace="home">
    
    <h1>Home Page</h1>
    <p>Content that will transition out...</p>
  </main>

  
  <footer>© 2025</footer>
</body>

三个关键元素:

  1. Wrapper(data-barba="wrapper")

    • 最外层容器
    • Wrapper 内、Container 外的所有内容都会保持不变
    • 适合放置不会变化的页眉、导航和页脚
  2. Container(data-barba="container")

    • 导航时会更新的动态内容区域
    • 过渡期间只有这部分会被替换
    • 每个页面都必须包含此元素
  3. Namespace(data-barba-namespace="home")

    • 每种页面类型的唯一标识符
    • 用于过渡规则和视图逻辑
    • 示例:"home"、"about"、"product"、"blog-post"
2. 过渡生命周期

Barba.js 为每次导航遵循精确的生命周期:

默认异步流程:

  1. 用户点击链接
  2. Barba 拦截导航
  3. 预获取下一页面(通过 AJAX)
  4. 缓存新内容
  5. Leave 钩子——将当前页面动画移出
  6. 等待移出动画完成
  7. 移除旧容器,插入新容器
  8. Enter 钩子——将新页面动画移入
  9. 等待移入动画完成
  10. 更新浏览器历史记录

同步流程(使用 sync: true):

  1. 用户点击链接
  2. Barba 拦截导航
  3. 预获取下一页面
  4. 等待新页面加载
  5. Leave 和 Enter 钩子同时运行(交叉淡化效果)
  6. 交换容器
  7. 更新浏览器历史记录
3. 钩子

Barba 提供 11 个生命周期钩子,用于控制过渡:

钩子执行顺序:

Initial page load:
  beforeOnce → once → afterOnce

Every navigation:
  before → beforeLeave → leave → afterLeave →
  beforeEnter → enter → afterEnter → after

钩子类型:

  • 全局钩子:在每次过渡时运行(barba.hooks.before())
  • 过渡钩子:在特定的过渡对象中定义
  • 视图钩子:在视图对象中定义,用于处理页面专属逻辑

常见钩子用途:

  • beforeLeave - 重置滚动位置,准备动画
  • leave - 将当前页面动画移出
  • afterLeave - 清理旧页面
  • beforeEnter - 准备新页面(隐藏元素、设置初始状态)
  • enter - 将新页面动画移入
  • afterEnter - 初始化页面脚本、跟踪分析数据
4. 视图

视图是页面专属逻辑容器,会根据 Namespace 运行:

barba.init({
  views: [{
    namespace: 'home',
    beforeEnter() {
      // Home-specific setup
      console.log('Entering home page');
    },
    afterEnter() {
      // Initialize home page features
      initHomeSlider();
    }
  }, {
    namespace: 'product',
    beforeEnter() {
      console.log('Entering product page');
    },
    afterEnter() {
      initProductGallery();
    }
  }]
});

常见模式

1. 基本设置

安装:

npm install --save-dev @barba/core
# or
yarn add @barba/core --dev

最简配置:

import barba from '@barba/core';

barba.init({
  transitions: [{
    name: 'default',
    leave({ current }) {
      // Fade out current page
      return gsap.to(current.container, {
        opacity: 0,
        duration: 0.5
      });
    },
    enter({ next }) {
      // Fade in new page
      return gsap.from(next.container, {
        opacity: 0,
        duration: 0.5
      });
    }
  }]
});
2. 淡入淡出过渡(异步)

经典的淡出、淡入过渡:

import barba from '@barba/core';
import gsap from 'gsap';

barba.init({
  transitions: [{
    name: 'fade',
    async leave({ current }) {
      await gsap.to(current.container, {
        opacity: 0,
        duration: 0.5,
        ease: 'power2.inOut'
      });
    },
    async enter({ next }) {
      // Start invisible
      gsap.set(next.container, { opacity: 0 });

      // Fade in
      await gsap.to(next.container, {
        opacity: 1,
        duration: 0.5,
        ease: 'power2.inOut'
      });
    }
  }]
});
3. 交叉淡化过渡(同步)

页面间同时进行淡化:

barba.init({
  transitions: [{
    name: 'crossfade',
    sync: true, // Enable sync mode
    leave({ current }) {
      return gsap.to(current.container, {
        opacity: 0,
        duration: 0.8,
        ease: 'power2.inOut'
      });
    },
    enter({ next }) {
      return gsap.from(next.container, {
        opacity: 0,
        duration: 0.8,
        ease: 'power2.inOut'
      });
    }
  }]
});
4. 带重叠效果的滑动过渡

将旧页面滑出,同时将新页面滑入:

barba.init({
  transitions: [{
    name: 'slide',
    sync: true,
    leave({ current }) {
      return gsap.to(current.container, {
        x: '-100%',
        duration: 0.7,
        ease: 'power3.inOut'
      });
    },
    enter({ next }) {
      // Start off-screen right
      gsap.set(next.container, { x: '100%' });

      // Slide in from right
      return gsap.to(next.container, {
        x: '0%',
        duration: 0.7,
        ease: 'power3.inOut'
      });
    }
  }]
});
5. 过渡规则(条件过渡)

根据导航上下文定义不同的过渡:

barba.init({
  transitions: [
    // Home to any page: fade
    {
      name: 'from-home-fade',
      from: { namespace: 'home' },
      leave({ current }) {
        return gsap.to(current.container, {
          opacity: 0,
          duration: 0.5
        });
      },
      enter({ next }) {
        return gsap.from(next.container, {
          opacity: 0,
          duration: 0.5
        });
      }
    },
    // Product to product: slide left
    {
      name: 'product-to-product',
      from: { namespace: 'product' },
      to: { namespace: 'product' },
      leave({ current }) {
        return gsap.to(current.container, {
          x: '-100%',
          duration: 0.6
        });
      },
      enter({ next }) {
        gsap.set(next.container, { x: '100%' });
        return gsap.to(next.container, {
          x: '0%',
          duration: 0.6
        });
      }
    },
    // Default fallback
    {
      name: 'default',
      leave({ current }) {
        return gsap.to(current.container, {
          opacity: 0,
          duration: 0.3
        });
      },
      enter({ next }) {
        return gsap.from(next.container, {
          opacity: 0,
          duration: 0.3
        });
      }
    }
  ]
});
6. 用于基于路由的过渡的 Router 插件

使用 @barba/router 实现特定路由的过渡:

安装:

npm install --save-dev @barba/router

用法:

import barba from '@barba/core';
import barbaPrefetch from '@barba/prefetch';
import barbaRouter from '@barba/router';

// Define routes
barbaRouter.init({
  routes: [
    { path: '/', name: 'home' },
    { path: '/about', name: 'about' },
    { path: '/products/:id', name: 'product' }, // Dynamic segment
    { path: '/blog/:category/:slug', name: 'blog-post' }
  ]
});

barba.use(barbaRouter);
barba.use(barbaPrefetch); // Optional: prefetch on hover

barba.init({
  transitions: [{
    name: 'product-transition',
    to: { route: 'product' }, // Trigger on route name
    leave({ current }) {
      return gsap.to(current.container, {
        scale: 0.95,
        opacity: 0,
        duration: 0.5
      });
    },
    enter({ next }) {
      return gsap.from(next.container, {
        scale: 1.05,
        opacity: 0,
        duration: 0.5
      });
    }
  }]
});
7. 加载指示器

在获取页面期间显示加载状态:

barba.init({
  transitions: [{
    async leave({ current }) {
      // Show loader
      const loader = document.querySelector('.loader');
      gsap.set(loader, { display: 'flex', opacity: 0 });
      gsap.to(loader, { opacity: 1, duration: 0.3 });

      // Fade out page
      await gsap.to(current.container, {
        opacity: 0,
        duration: 0.5
      });
    },
    async enter({ next }) {
      // Hide loader
      const loader = document.querySelector('.loader');
      await gsap.to(loader, { opacity: 0, duration: 0.3 });
      gsap.set(loader, { display: 'none' });

      // Fade in page
      await gsap.from(next.container, {
        opacity: 0,
        duration: 0.5
      });
    }
  }]
});

集成模式

GSAP 集成

Barba.js 可与 GSAP 无缝配合,实现动画效果:

基于时间线的过渡:

import barba from '@barba/core';
import gsap from 'gsap';

barba.init({
  transitions: [{
    async leave({ current }) {
      const tl = gsap.timeline();

      tl.to(current.container.querySelector('h1'), {
        y: -50,
        opacity: 0,
        duration: 0.3
      })
      .to(current.container.querySelector('.content'), {
        y: -30,
        opacity: 0,
        duration: 0.3
      }, '-=0.2')
      .to(current.container, {
        opacity: 0,
        duration: 0.2
      });

      await tl.play();
    },
    async enter({ next }) {
      const tl = gsap.timeline();

      // Set initial states
      gsap.set(next.container, { opacity: 0 });
      gsap.set(next.container.querySelector('h1'), { y: 50, opacity: 0 });
      gsap.set(next.container.querySelector('.content'), { y: 30, opacity: 0 });

      tl.to(next.container, {
        opacity: 1,
        duration: 0.2
      })
      .to(next.container.querySelector('h1'), {
        y: 0,
        opacity: 1,
        duration: 0.5,
        ease: 'power3.out'
      })
      .to(next.container.querySelector('.content'), {
        y: 0,
        opacity: 1,
        duration: 0.5,
        ease: 'power3.out'
      }, '-=0.3');

      await tl.play();
    }
  }]
});

参考 gsap-scrolltrigger 技能,了解高级 GSAP 集成模式。

按视图初始化

按页面初始化库或脚本:

barba.init({
  views: [
    {
      namespace: 'home',
      afterEnter() {
        // Initialize home page features
        initHomepageSlider();
        initParallaxEffects();
      },
      beforeLeave() {
        // Clean up
        destroyHomepageSlider();
      }
    },
    {
      namespace: 'gallery',
      afterEnter() {
        initLightbox();
        initMasonry();
      },
      beforeLeave() {
        destroyLightbox();
      }
    }
  ]
});
分析跟踪

在导航时跟踪页面浏览量:

barba.hooks.after(() => {
  // Google Analytics
  if (typeof gtag !== 'undefined') {
    gtag('config', 'GA_MEASUREMENT_ID', {
      page_path: window.location.pathname
    });
  }

  // Or use data layer
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push({
    event: 'pageview',
    page: window.location.pathname
  });
});
第三方脚本重新初始化

在页面过渡后重新运行脚本:

barba.hooks.after(() => {
  // Re-initialize third-party widgets
  if (typeof twttr !== 'undefined') {
    twttr.widgets.load(); // Twitter widgets
  }

  if (typeof FB !== 'undefined') {
    FB.XFBML.parse(); // Facebook widgets
  }

  // Re-run syntax highlighting
  if (typeof Prism !== 'undefined') {
    Prism.highlightAll();
  }
});

性能优化

1. 预获取

使用 @barba/prefetch 在悬停时加载页面:

npm install --save-dev @barba/prefetch
import barba from '@barba/core';
import barbaPrefetch from '@barba/prefetch';

barba.use(barbaPrefetch);

barba.init({
  // Prefetch fires on link hover by default
  prefetch: {
    root: null, // Observe all links
    timeout: 3000 // Cache timeout in ms
  }
});
2. 防止布局偏移

设置容器的最小高度,防止内容跳动:

[data-barba="container"] {
  min-height: 100vh;
  /* Or use viewport height minus header/footer */
  min-height: calc(100vh - 80px - 60px);
}
3. 优化动画

使用 GPU 加速属性:

// ✅ Good - GPU accelerated
gsap.to(element, {
  opacity: 0,
  x: -100,
  scale: 0.9,
  rotation: 45
});

// ❌ Avoid - causes reflow/repaint
gsap.to(element, {
  width: '50%',
  height: '300px',
  top: '100px'
});
4. 清理事件监听器

在 beforeLeave 或视图钩子中移除监听器:

barba.init({
  views: [{
    namespace: 'home',
    afterEnter() {
      // Add listeners
      this.clickHandler = () => console.log('clicked');
      document.querySelector('.btn').addEventListener('click', this.clickHandler);
    },
    beforeLeave() {
      // Remove listeners
      document.querySelector('.btn').removeEventListener('click', this.clickHandler);
    }
  }]
});
5. 延迟加载图像

将图像加载推迟到过渡完成后:

barba.init({
  transitions: [{
    async enter({ next }) {
      // Complete transition first
      await gsap.from(next.container, {
        opacity: 0,
        duration: 0.5
      });

      // Then load images
      const images = next.container.querySelectorAll('img[data-src]');
      images.forEach(img => {
        img.src = img.dataset.src;
        img.removeAttribute('data-src');
      });
    }
  }]
});

常见问题

1. 忘记返回 Promise

问题:过渡会立即完成,而不会等待动画结束。

解决方案:始终返回 Promise,或使用 async/await:

// ❌ Wrong - animation starts but doesn't wait
leave({ current }) {
  gsap.to(current.container, { opacity: 0, duration: 0.5 });
}

// ✅ Correct - returns promise
leave({ current }) {
  return gsap.to(current.container, { opacity: 0, duration: 0.5 });
}

// ✅ Also correct - async/await
async leave({ current }) {
  await gsap.to(current.container, { opacity: 0, duration: 0.5 });
}
2. 未阻止链接的默认行为

问题:某些链接会导致整个页面重新加载。

解决方案:Barba 会自动阻止内部链接的默认行为,但你可能需要排除外部链接:

barba.init({
  prevent: ({ href }) => {
    // Allow external links
    if (href.indexOf('http') > -1 && href.indexOf(window.location.host) === -1) {
      return true;
    }
    return false;
  }
});
3. 页面间的 CSS 冲突

问题:旧页面的 CSS 会在过渡期间影响新页面的布局。

解决方案:使用特定命名空间的 CSS,或重置样式:

/* Namespace-specific styles */
[data-barba-namespace="home"] .hero {
  background: blue;
}

[data-barba-namespace="about"] .hero {
  background: red;
}

或者在 beforeEnter 中重置:

beforeEnter({ next }) {
  // Reset scroll position
  window.scrollTo(0, 0);

  // Reset any global state
  document.body.classList.remove('menu-open');
}
4. 未更新文档标题和 Meta 标签

问题:导航时页面标题和 Meta 标签不会更新。

解决方案:使用 @barba/head 插件或手动更新:

npm install --save-dev @barba/head
import barba from '@barba/core';
import barbaHead from '@barba/head';

barba.use(barbaHead);

barba.init({
  // Head plugin automatically updates <head> tags
});

或者手动更新:

barba.hooks.after(({ next }) => {
  // Update title
  document.title = next.html.querySelector('title').textContent;

  // Update meta tags
  const newMeta = next.html.querySelectorAll('meta');
  newMeta.forEach(meta => {
    const name = meta.getAttribute('name') || meta.getAttribute('property');
    if (name) {
      const existing = document.querySelector(`meta[name="${name}"], meta[property="${name}"]`);
      if (existing) {
        existing.setAttribute('content', meta.getAttribute('content'));
      }
    }
  });
});
5. 页面进入时动画闪烁

问题:新页面会在进入动画开始前闪现。

解决方案:在 CSS 或 beforeEnter 中设置初始不可见状态:

/* CSS approach */
[data-barba="container"] {
  opacity: 0;
}

[data-barba="container"].is-visible {
  opacity: 1;
}
// JavaScript approach
beforeEnter({ next }) {
  gsap.set(next.container, { opacity: 0 });
}
6. 同步过渡时未正确设置位置

问题:容器堆叠会导致同步过渡时发生布局偏移。

解决方案:在过渡期间将容器设为绝对定位:

[data-barba="wrapper"] {
  position: relative;
}

[data-barba="container"] {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
}

或者通过 JavaScript 管理:

barba.init({
  transitions: [{
    sync: true,
    beforeLeave({ current }) {
      gsap.set(current.container, {
        position: 'absolute',
        top: 0,
        left: 0,
        width: '100%'
      });
    }
  }]
});

资源

此技能包括:

scripts/

用于执行常见 Barba.js 任务的实用工具:

  • transition_generator.py - 生成过渡样板代码
  • project_setup.py - 初始化 Barba.js 项目结构
references/

详细文档:

  • api_reference.md - 完整的 Barba.js API(钩子、过渡、视图、路由器)
  • hooks_guide.md - 全部 11 个钩子的执行顺序和使用场景
  • gsap_integration.md - Barba 过渡的 GSAP 动画模式
  • transition_patterns.md - 常见的过渡实现方式
assets/

模板和入门项目:

  • starter_barba/ - 完整的 Barba.js + GSAP 入门模板
  • examples/ - 实际过渡实现示例

相关技能

  • gsap-scrolltrigger - 用于过渡中的高级 GSAP 动画
  • locomotive-scroll - 可与 Barba 结合,实现页面间的平滑滚动
  • motion-framer - React 页面过渡的替代方案

评论

支持 Markdown