跳至主要内容 跳至文档导航

根据滚动位置自动更新 Bootstrap 导航或列表组组件,以指示当前视口中哪个链接处于活动状态。

工作原理

当锚点 (<a>) 元素引用的 id 元素滚动到视图中时,Scrollspy 会切换锚点的 .active 类。Scrollspy 最好与 Bootstrap 导航组件列表组 结合使用,但它也可以与当前页面中的任何锚点元素一起使用。以下是其工作原理。

  • 首先,scrollspy 需要两样东西:导航、列表组或一组简单的链接,以及一个可滚动容器。可滚动容器可以是 <body> 或具有设置的 heightoverflow-y: scroll 的自定义元素。

  • 在可滚动容器上,添加 data-bs-spy="scroll"data-bs-target="#navId",其中 navId 是关联导航的唯一 id。如果元素内部没有可聚焦元素,请务必同时包含 tabindex="0" 以确保键盘访问。

  • 当您滚动“监视”容器时,关联导航中的锚点链接会添加和删除 .active 类。链接必须具有可解析的 id 目标,否则将被忽略。例如,<a href="#home">home</a> 必须对应于 DOM 中的类似内容 <div id="home"></div>

  • 将忽略不可见的元素。请参阅下面的 不可见元素 部分。

示例

滚动导航栏下方的区域,观察活动类发生变化。打开下拉菜单,观察下拉菜单项也突出显示。

第一标题

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

第二标题

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

第三标题

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

第四标题

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

第五标题

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

<nav id="navbar-example2" class="navbar bg-body-tertiary px-3 mb-3">
  <a class="navbar-brand" href="#">Navbar</a>
  <ul class="nav nav-pills">
    <li class="nav-item">
      <a class="nav-link" href="#scrollspyHeading1">First</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#scrollspyHeading2">Second</a>
    </li>
    <li class="nav-item dropdown">
      <a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">Dropdown</a>
      <ul class="dropdown-menu">
        <li><a class="dropdown-item" href="#scrollspyHeading3">Third</a></li>
        <li><a class="dropdown-item" href="#scrollspyHeading4">Fourth</a></li>
        <li><hr class="dropdown-divider"></li>
        <li><a class="dropdown-item" href="#scrollspyHeading5">Fifth</a></li>
      </ul>
    </li>
  </ul>
</nav>
<div data-bs-spy="scroll" data-bs-target="#navbar-example2" data-bs-root-margin="0px 0px -40%" data-bs-smooth-scroll="true" class="scrollspy-example bg-body-tertiary p-3 rounded-2" tabindex="0">
  <h4 id="scrollspyHeading1">First heading</h4>
  <p>...</p>
  <h4 id="scrollspyHeading2">Second heading</h4>
  <p>...</p>
  <h4 id="scrollspyHeading3">Third heading</h4>
  <p>...</p>
  <h4 id="scrollspyHeading4">Fourth heading</h4>
  <p>...</p>
  <h4 id="scrollspyHeading5">Fifth heading</h4>
  <p>...</p>
</div>

嵌套导航

滚动间谍还适用于嵌套的 .nav。如果嵌套的 .nav.active,则其父级也将为 .active。滚动导航栏旁边的区域,观察活动类发生变化。

项目 1

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

请记住,JavaScript 插件会尝试在所有可能可见的元素中选择正确的元素。同时有多个可见的滚动间谍目标可能会导致一些问题。

项目 1-1

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

请记住,JavaScript 插件会尝试在所有可能可见的元素中选择正确的元素。同时有多个可见的滚动间谍目标可能会导致一些问题。

项目 1-2

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

请记住,JavaScript 插件会尝试在所有可能可见的元素中选择正确的元素。同时有多个可见的滚动间谍目标可能会导致一些问题。

项目 2

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

请记住,JavaScript 插件会尝试在所有可能可见的元素中选择正确的元素。同时有多个可见的滚动间谍目标可能会导致一些问题。

项目 3

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

请记住,JavaScript 插件会尝试在所有可能可见的元素中选择正确的元素。同时有多个可见的滚动间谍目标可能会导致一些问题。

项目 3-1

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

请记住,JavaScript 插件会尝试在所有可能可见的元素中选择正确的元素。同时有多个可见的滚动间谍目标可能会导致一些问题。

项目 3-2

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

请记住,JavaScript 插件会尝试在所有可能可见的元素中选择正确的元素。同时有多个可见的滚动间谍目标可能会导致一些问题。

<div class="row">
  <div class="col-4">
    <nav id="navbar-example3" class="h-100 flex-column align-items-stretch pe-4 border-end">
      <nav class="nav nav-pills flex-column">
        <a class="nav-link" href="#item-1">Item 1</a>
        <nav class="nav nav-pills flex-column">
          <a class="nav-link ms-3 my-1" href="#item-1-1">Item 1-1</a>
          <a class="nav-link ms-3 my-1" href="#item-1-2">Item 1-2</a>
        </nav>
        <a class="nav-link" href="#item-2">Item 2</a>
        <a class="nav-link" href="#item-3">Item 3</a>
        <nav class="nav nav-pills flex-column">
          <a class="nav-link ms-3 my-1" href="#item-3-1">Item 3-1</a>
          <a class="nav-link ms-3 my-1" href="#item-3-2">Item 3-2</a>
        </nav>
      </nav>
    </nav>
  </div>

  <div class="col-8">
    <div data-bs-spy="scroll" data-bs-target="#navbar-example3" data-bs-smooth-scroll="true" class="scrollspy-example-2" tabindex="0">
      <div id="item-1">
        <h4>Item 1</h4>
        <p>...</p>
      </div>
      <div id="item-1-1">
        <h5>Item 1-1</h5>
        <p>...</p>
      </div>
      <div id="item-1-2">
        <h5>Item 1-2</h5>
        <p>...</p>
      </div>
      <div id="item-2">
        <h4>Item 2</h4>
        <p>...</p>
      </div>
      <div id="item-3">
        <h4>Item 3</h4>
        <p>...</p>
      </div>
      <div id="item-3-1">
        <h5>Item 3-1</h5>
        <p>...</p>
      </div>
      <div id="item-3-2">
        <h5>Item 3-2</h5>
        <p>...</p>
      </div>
    </div>
  </div>
</div>

列表组

滚动间谍还适用于 .list-group。滚动列表组旁边的区域,观察活动类发生变化。

项目 1

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

项目 2

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

项目 3

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

项目 4

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

<div class="row">
  <div class="col-4">
    <div id="list-example" class="list-group">
      <a class="list-group-item list-group-item-action" href="#list-item-1">Item 1</a>
      <a class="list-group-item list-group-item-action" href="#list-item-2">Item 2</a>
      <a class="list-group-item list-group-item-action" href="#list-item-3">Item 3</a>
      <a class="list-group-item list-group-item-action" href="#list-item-4">Item 4</a>
    </div>
  </div>
  <div class="col-8">
    <div data-bs-spy="scroll" data-bs-target="#list-example" data-bs-smooth-scroll="true" class="scrollspy-example" tabindex="0">
      <h4 id="list-item-1">Item 1</h4>
      <p>...</p>
      <h4 id="list-item-2">Item 2</h4>
      <p>...</p>
      <h4 id="list-item-3">Item 3</h4>
      <p>...</p>
      <h4 id="list-item-4">Item 4</h4>
      <p>...</p>
    </div>
  </div>
</div>

简单锚点

滚动间谍不限于导航组件和列表组,因此它适用于当前文档中的任何 <a> 锚点元素。滚动区域,观察 .active 类发生变化。

项目 1

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

项目 2

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

项目 3

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

项目 4

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

项目 5

这是滚动间谍页面的占位内容。请注意,当您向下滚动页面时,相应的导航链接会突出显示。它在组件示例中重复出现。我们不断在此处添加更多示例副本,以强调滚动和突出显示。

<div class="row">
  <div class="col-4">
    <div id="simple-list-example" class="d-flex flex-column gap-2 simple-list-example-scrollspy text-center">
      <a class="p-1 rounded" href="#simple-list-item-1">Item 1</a>
      <a class="p-1 rounded" href="#simple-list-item-2">Item 2</a>
      <a class="p-1 rounded" href="#simple-list-item-3">Item 3</a>
      <a class="p-1 rounded" href="#simple-list-item-4">Item 4</a>
      <a class="p-1 rounded" href="#simple-list-item-5">Item 5</a>
    </div>
  </div>
  <div class="col-8">
    <div data-bs-spy="scroll" data-bs-target="#simple-list-example" data-bs-offset="0" data-bs-smooth-scroll="true" class="scrollspy-example" tabindex="0">
      <h4 id="simple-list-item-1">Item 1</h4>
      <p>...</p>
      <h4 id="simple-list-item-2">Item 2</h4>
      <p>...</p>
      <h4 id="simple-list-item-3">Item 3</h4>
      <p>...</p>
      <h4 id="simple-list-item-4">Item 4</h4>
      <p>...</p>
      <h4 id="simple-list-item-5">Item 5</h4>
      <p>...</p>
    </div>
  </div>
</div>

不可见元素

不可见的元素将被忽略,其对应的导航项不会收到 .active 类。在不可见包装器中初始化的 Scrollspy 实例将忽略所有目标元素。包装器变为可见后,使用 refresh 方法检查可观察元素。

document.querySelectorAll('#nav-tab>[data-bs-toggle="tab"]').forEach(el => {
  el.addEventListener('shown.bs.tab', () => {
    const target = el.getAttribute('data-bs-target')
    const scrollElem = document.querySelector(`${target} [data-bs-spy="scroll"]`)
    bootstrap.ScrollSpy.getOrCreateInstance(scrollElem).refresh()
  })
})

用法

通过数据属性

要轻松地将 Scrollspy 行为添加到顶部导航栏,请将 data-bs-spy="scroll" 添加到要监视的元素(通常是 <body>)。然后添加 data-bs-target 属性,其中包含任何 Bootstrap .nav 组件的父元素的 id 或类名。

<body data-bs-spy="scroll" data-bs-target="#navbar-example">
  ...
  <div id="navbar-example">
    <ul class="nav nav-tabs" role="tablist">
      ...
    </ul>
  </div>
  ...
</body>

通过 JavaScript

const scrollSpy = new bootstrap.ScrollSpy(document.body, {
  target: '#navbar-example'
})

选项

由于可以通过数据属性或 JavaScript 传递选项,因此可以将选项名称附加到 data-bs-,如 data-bs-animation="{value}"。通过数据属性传递选项时,请务必将选项名称的类型从“camelCase”更改为“kebab-case”。例如,使用 data-bs-custom-class="beautifier" 而不是 data-bs-customClass="beautifier"

从 Bootstrap 5.2.0 开始,所有组件都支持一个实验性保留数据属性 data-bs-config,它可以将简单的组件配置作为 JSON 字符串容纳在其中。当一个元素具有 data-bs-config='{"delay":0, "title":123}'data-bs-title="456" 属性时,最终的 title 值将为 456,单独的数据属性将覆盖 data-bs-config 上给出的值。此外,现有数据属性能够容纳 JSON 值,如 data-bs-delay='{"show":0,"hide":150}'

最终的配置对象是 data-bs-configdata-bs-js 对象 的合并结果,其中最新给定的键值将覆盖其他键值。

名称 类型 默认值 描述
rootMargin 字符串 0px 0px -25% 计算滚动位置时,Intersection Observer rootMargin 有效单位。
smoothScroll 布尔值 false 当用户点击指向 ScrollSpy 可观察对象的链接时,启用平滑滚动。
target 字符串、DOM 元素 null 指定要应用 Scrollspy 插件的元素。
threshold 数组 [0.1, 0.5, 1] IntersectionObserver threshold 在计算滚动位置时有效的输入。

已弃用的选项

在 v5.1.3 之前,我们使用 offsetmethod 选项,它们现在已弃用并被 rootMargin 取代。为了保持向后兼容性,我们将继续将给定的 offset 解析为 rootMargin,但此功能将在 v6 中删除。

方法

方法 描述
dispose 销毁元素的 scrollspy。(移除 DOM 元素上存储的数据)
getInstance 静态方法,用于获取与 DOM 元素关联的 scrollspy 实例。
getOrCreateInstance 静态方法,用于获取与 DOM 元素关联的 scrollspy 实例,或在未初始化的情况下创建一个新的实例。
refresh 在 DOM 中添加或移除元素时,你需要调用 refresh 方法。

以下是使用 refresh 方法的一个示例

const dataSpyList = document.querySelectorAll('[data-bs-spy="scroll"]')
dataSpyList.forEach(dataSpyEl => {
  bootstrap.ScrollSpy.getInstance(dataSpyEl).refresh()
})

事件

事件 描述
activate.bs.scrollspy 每当 scrollspy 激活锚点时,此事件就会在滚动元素上触发。
const firstScrollSpyEl = document.querySelector('[data-bs-spy="scroll"]')
firstScrollSpyEl.addEventListener('activate.bs.scrollspy', () => {
  // do something...
})