スクロール位置に基づいてBootstrapのナビゲーションまたはリストグループコンポーネントを自動的に更新し、ビューポートで現在アクティブなリンクを示すようにします。
仕組み
v-b-scrollspy
ディレクティブが正常に機能するには、いくつかの要件があります。
- 現在アクティブなリンクを示す
<b-nav>
または<b-list-group>
コンポーネントが含まれている要素/コンポーネントに適用する必要があります。 - Scrollspyは、監視対象の要素(通常は
<body>
)にposition: relative;
を必要とします。 <body>
以外の要素を監視する場合は、height
が設定され、overflow-y: scroll;
が適用されていることを確認してください。 - アンカー(
<a>
、<b-nav-item>
、<b-dropdown-item>
、<b-list-group-item>
)は必須であり、監視対象のコンテナ内のそのid
を持つ要素を指すhref
(href
またはto
プロパティを介して)が必要です。to
プロパティを使用する場合は、#id-of-element
で終わるpath
を設定するか、locationプロパティhash
を#id-of-element
に設定します。
正常に実装されると、ナビゲーションまたはリストグループがそれに応じて更新され、関連付けられたターゲットに基づいて、ある項目から次の項目にactive
状態が移動します。
ナビゲーションを使用した例
<b-nav>
コンポーネントでv-b-scrollspy
を使用して、<b-card-body>
のスクロールを監視します。ナビバーの下の領域をスクロールして、アクティブクラスが変化するのを見てください。ドロップダウン項目も強調表示されます。
<template>
<div>
<b-card no-body>
<b-nav pills card-header slot="header" v-b-scrollspy:nav-scroller>
<b-nav-item href="#fat" @click="scrollIntoView">@fat</b-nav-item>
<b-nav-item href="#mdo" @click="scrollIntoView">@mdo</b-nav-item>
<b-nav-item-dropdown text="Dropdown 1,2,3" right-alignment>
<b-dropdown-item href="#one" @click="scrollIntoView">one</b-dropdown-item>
<b-dropdown-item href="#two" @click="scrollIntoView">two</b-dropdown-item>
<b-dropdown-divider></b-dropdown-divider>
<b-dropdown-item href="#three" @click="scrollIntoView">three</b-dropdown-item>
</b-nav-item-dropdown>
<b-nav-item href="#pi0" @click="scrollIntoView">@pi0</b-nav-item>
</b-nav>
<b-card-body
id="nav-scroller"
ref="content"
style="position:relative; height:300px; overflow-y:scroll;"
>
<p>{{ text }}</p>
<h4 id="fat">@fat</h4>
<p v-for="i in 3">{{ text }}</p>
<h4 id="mdo">@mdo</h4>
<p v-for="i in 3">{{ text }}</p>
<h4 id="one">one</h4>
<p v-for="i in 2">{{ text }}</p>
<h4 id="two">two</h4>
<p>{{ text }}</p>
<h4 id="three">three</h4>
<p v-for="i in 2">{{ text }}</p>
<h4 id="pi0">@pi0</h4>
<p v-for="i in 3">{{ text }}</p>
</b-card-body>
</b-card>
</div>
</template>
<script>
export default {
methods: {
scrollIntoView(event) {
event.preventDefault()
const href = event.target.getAttribute('href')
const el = href ? document.querySelector(href) : null
if (el) {
this.$refs.content.scrollTop = el.offsetTop
}
}
},
data() {
return {
text: `
Quis magna Lorem anim amet ipsum do mollit sit cillum voluptate ex nulla
tempor. Laborum consequat non elit enim exercitation cillum aliqua
consequat id aliqua. Esse ex consectetur mollit voluptate est in duis
laboris ad sit ipsum anim Lorem. Incididunt veniam velit elit elit veniam
Lorem aliqua quis ullamco deserunt sit enim elit aliqua esse irure. Laborum
nisi sit est tempor laborum mollit labore officia laborum excepteur
commodo non commodo dolor excepteur commodo. Ipsum fugiat ex est consectetur
ipsum commodo tempor sunt in proident.
`
}
}
}
</script>
ネストされたナビゲーションを使用した例
Scrollspyは、ネストされた<b-nav>
でも機能します。ネストされた<b-nav-item>
がアクティブな場合、その親もアクティブになります。ナビバーの横の領域をスクロールして、アクティブクラスが変化するのを見てください。
<template>
<b-container fluid>
<b-row>
<b-col cols="4">
<b-navbar v-b-scrollspy:scrollspy-nested class="flex-column">
<b-navbar-brand href="#">Navbar</b-navbar-brand>
<b-nav pills vertical>
<b-nav-item href="#item-1">Item 1</b-nav-item>
<b-nav pills vertical>
<b-nav-item class="ml-3 my-1" href="#item-1-1">Item 1-1</b-nav-item>
<b-nav-item class="ml-3 my-1" href="#item-1-2">Item 1-2</b-nav-item>
</b-nav>
<b-nav-item href="#item-2">Item 2</b-nav-item>
<b-nav-item href="#item-3">Item 3</b-nav-item>
<b-nav pills vertical>
<b-nav-item class="ml-3 my-1" href="#item-3-1">Item 3-1</b-nav-item>
<b-nav-item class="ml-3 my-1" href="#item-3-2">Item 3-2</b-nav-item>
</b-nav>
</b-nav>
</b-navbar>
</b-col>
<b-col cols="8">
<div id="scrollspy-nested" style="position:relative; height:350px; overflow-y:auto">
<h4 id="item-1" style="">Item 1</h4>
<p>{{ text }}</p>
<h5 id="item-1-1" style="">Item 1-1</h5>
<p>{{ text }}</p>
<h5 id="item-1-2" style="">Item 2-2</h5>
<p>{{ text }}</p>
<h4 id="item-2" style="">Item 2</h4>
<p>{{ text }}</p>
<h4 id="item-3" style="">Item 3</h4>
<p>{{ text }}</p>
<h5 id="item-3-1" style="">Item 3-1</h5>
<p>{{ text }}</p>
<h5 id="item-3-2" style="">Item 3-2</h5>
<p>{{ text }}</p>
</div>
</b-col>
</b-row>
</b-container>
</template>
<script>
export default {
data() {
return {
text: `
Quis magna Lorem anim amet ipsum do mollit sit cillum voluptate ex nulla
tempor. Laborum consequat non elit enim exercitation cillum aliqua
consequat id aliqua. Esse ex consectetur mollit voluptate est in duis
laboris ad sit ipsum anim Lorem. Incididunt veniam velit elit elit veniam
Lorem aliqua quis ullamco deserunt sit enim elit aliqua esse irure. Laborum
nisi sit est tempor laborum mollit labore officia laborum excepteur
commodo non commodo dolor excepteur commodo. Ipsum fugiat ex est consectetur
ipsum commodo tempor sunt in proident.
`
}
}
}
</script>
リストグループを使用した例
Scrollspyは、ローカルのhref
またはto
を持つ<b-list-group-item>
が含まれている場合、<b-list-group>
でも機能します。リストグループの横の領域をスクロールして、アクティブな状態が変化するのを見てください。
<template>
<b-container fluid>
<b-row>
<b-col cols="4">
<b-list-group v-b-scrollspy:listgroup-ex>
<b-list-group-item href="#list-item-1">Item 1</b-list-group-item>
<b-list-group-item href="#list-item-2">Item2</b-list-group-item>
<b-list-group-item href="#list-item-3">Item 3</b-list-group-item>
<b-list-group-item href="#list-item-4">Item 4</b-list-group-item>
<b-list-group-item href="#list-item-5">Item 5</b-list-group-item>
</b-list-group>
</b-col>
<b-col cols="8">
<div id="listgroup-ex" style="position:relative; overflow-y:auto; height:300px">
<h4 id="list-item-1">Item 1</h4>
<p>{{ text }}</p>
<h4 id="list-item-2">Item 2</h4>
<p>{{ text }}</p>
<h4 id="list-item-3">Item 3</h4>
<p>{{ text }}</p>
<h4 id="list-item-4">Item 4</h4>
<p>{{ text }}</p>
<h4 id="list-item-5">Item 5</h4>
<p>{{ text }}</p>
</div>
</b-col>
</b-row>
</b-container>
</template>
<script>
export default {
data() {
return {
text: `
Quis magna Lorem anim amet ipsum do mollit sit cillum voluptate ex nulla
tempor. Laborum consequat non elit enim exercitation cillum aliqua
consequat id aliqua. Esse ex consectetur mollit voluptate est in duis
laboris ad sit ipsum anim Lorem. Incididunt veniam velit elit elit veniam
Lorem aliqua quis ullamco deserunt sit enim elit aliqua esse irure. Laborum
nisi sit est tempor laborum mollit labore officia laborum excepteur
commodo non commodo dolor excepteur commodo. Ipsum fugiat ex est consectetur
ipsum commodo tempor sunt in proident.
`
}
}
}
</script>
Vue Router(またはNuxt.js)を使用しており、to
プロパティでリンクを生成している場合は、次のいずれかの方法を使用して、レンダリングされたリンクに適切なhref
を生成します。
<b-nav-item to="#id-of-element">link text</b-nav-item>
<b-nav-item :to="{ hash: '#id-of-element' }">link text</b-nav-item>
Scrollspyは、生成されたURLが#id-of-element
で終わる限り、history
ルーティングモードとhash
ルーティングモードの両方で機能します。
ディレクティブの構文と使い方
v-b-scrollspy:arg.mod1.mod2="option"
ここで
arg
は、スクロールを監視する要素のID(#
を除く)です。オプション(デフォルトはbody
)。option
でオーバーライドできます) mod1
とmod2
は、offset
の数値または文字列のmethod
にすることができます(以下の設定オブジェクトを参照)。修飾子の順序は重要ではありません。どちらもオプションです option
は、スクロールを監視するelement
を識別する文字列、数値offset
、または設定オブジェクト(下記参照)にすることができます。オプション
注:このディレクティブは、ネイティブのBootstrap v4とは逆方向に適用されます。BootstrapVueでは、v-b-scrollspy
ディレクティブは、アクティブ化されるリンクを持つターゲット要素に適用され、argまたはoptionは、スクロールを監視(スパイ)する要素を指定します。
このディレクティブは、<nav-item>
、<b-dropdown-item>
、<b-list-group-item>
(または適切なクラスを持つ<a>
タグ)を持つ任意のコンテナ要素またはコンポーネントに適用できます。スクロール要素内のそれぞれのid
を持つ要素を指すhref
属性がレンダリングされている限り。
設定オブジェクトのプロパティ
const config = {
element: 'body',
offset: 10,
method: 'auto',
throttle: 100
}
プロパティ | タイプ | デフォルト | 説明 |
element | 文字列または参照 | 'body' | スクロールを監視する要素。ID(#foo )、CSSセレクター(#foo div )、または要素/コンポーネントノードへの参照にすることができます。CSS文字列の場合、最初に一致する要素が使用されます。IDを使用する場合は、# で始める必要があります。 |
offset | 数値 | 10 | アクティブ状態をトリガーする前の、スクロールビューポートの上部からのオフセット(ピクセル単位)。 |
method | 文字列 | 'auto' | position は、スクロールコンテナに対するターゲットオフセットを計算します。offset は、ウィンドウ/ビューポートの上部に対するターゲットオフセットを計算します。auto は、スクロール要素がbody の場合はoffset を選択し、それ以外の場合はposition を選択します。 |
throttle | 数値 | 100 | オフセットを再計算する前に、リサイズイベントの発火を停止するまでのタイムアウト(ms 単位)。 |
引数/修飾子と値(オブジェクトまたは数値)が渡された場合、値は引数と修飾子よりも優先されます。
オプションのいずれかが無効なタイプの場合、エラーがコンソールに書き込まれます。
設定に関する注意事項
- スクロール要素が存在しない場合は、
<body>
でスクロールしていると見なします。 - スクロール要素がCSSセレクターの場合、最初に見つかった要素が選択されます。
- スクロール要素が見つからない場合、Scrollspyは何もせずにサイレントに実行されます。
重要!相対ポジショニングが必要です 実装方法に関係なく、scrollspyでは、スクロールしている要素にposition: relative;
を使用する必要があります。ほとんどの場合、これは<body>
です。<body>
以外の要素でscrollspyingする場合は、CSSのheight
が設定され、overflow-y: scroll;
が適用されていることを確認してください。
ディレクティブの使用例
<body>
がスクロール要素であり、デフォルトのオフセットを10ピクセルと仮定します。
<div>
<b-nav v-b-scrollspy>
<b-nav-item href="#bar">Foo</b-nav-item>
<b-nav-item href="#baz">Bar</b-nav-item>
</b-nav>
</div>
<body>
がスクロール要素であり、オフセットを20ピクセルと仮定します。
<div>
<b-nav v-b-scrollspy="20">
<b-nav-item href="#bar">Foo</b-nav-item>
<b-nav-item href="#baz">Bar</b-nav-item>
</b-nav>
</div>
IDが#foo
の要素がスクロール要素であり、デフォルトのオフセットを10ピクセルと仮定します。
<div>
<b-nav v-b-scrollspy:foo>
<b-nav-item href="#bar">Foo</b-nav-item>
<b-nav-item href="#baz">Bar</b-nav-item>
</b-nav>
</div>
要素#foo
がスクロール要素であり、オフセットを20ピクセルと仮定します。
<div>
<b-nav v-b-scrollspy:foo="20">
<b-nav-item href="#bar">Foo</b-nav-item>
<b-nav-item href="#baz">Bar</b-nav-item>
</b-nav>
</div>
要素#foo
がスクロール要素であり、オフセットを25ピクセルと仮定します。
<div>
<b-nav v-b-scrollspy:foo.25>
<b-nav-item href="#bar">Foo</b-nav-item>
<b-nav-item href="#baz">Bar</b-nav-item>
</b-nav>
</div>
要素#foo
がスクロール要素であり、デフォルトのオフセットを10ピクセルと仮定します(値の周りの単一引用符に注意してください)。
<div>
<b-nav v-b-scrollspy="'#foo'">
<b-nav-item href="#bar">Foo</b-nav-item>
<b-nav-item href="#baz">Bar</b-nav-item>
</b-nav>
</div>
オブジェクトを設定として渡します。element
は、CSS ID(例:#foo
)、CSSセレクター(例:body
)、またはノード参照にすることができます。
<div>
<b-nav v-b-scrollspy="{element: '#id', offset: 50}">
<b-nav-item href="#bar">Foo</b-nav-item>
<b-nav-item href="#baz">Bar</b-nav-item>
</b-nav>
</div>
イベント
ターゲットがアクティブになるたびに、イベントbv:scrollspy::activate
が$root
上で、ターゲットのIDを引数として(例:#bar
)発行されます。
const app = new Vue({
el: '#app',
created() {
this.$root.$on('bv::scrollspy::activate', this.onActivate)
},
methods: {
onActivate(target) {
console.log('Received event: "bv::scrollspy::activate" for target ', target)
}
}
})