mirror of
https://github.com/twbs/bootstrap.git
synced 2025-08-12 08:34:08 +02:00
ScrollSpy: make the threshold option configurable (#36750)
* feat(ScrollSpy): make the threshold option configurable
This commit is contained in:
@@ -40,14 +40,16 @@ const Default = {
|
|||||||
offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons
|
offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons
|
||||||
rootMargin: '0px 0px -25%',
|
rootMargin: '0px 0px -25%',
|
||||||
smoothScroll: false,
|
smoothScroll: false,
|
||||||
target: null
|
target: null,
|
||||||
|
threshold: [0.1, 0.5, 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
const DefaultType = {
|
const DefaultType = {
|
||||||
offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons
|
offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons
|
||||||
rootMargin: 'string',
|
rootMargin: 'string',
|
||||||
smoothScroll: 'boolean',
|
smoothScroll: 'boolean',
|
||||||
target: 'element'
|
target: 'element',
|
||||||
|
threshold: 'array'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -110,6 +112,13 @@ class ScrollSpy extends BaseComponent {
|
|||||||
// TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case
|
// TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case
|
||||||
config.target = getElement(config.target) || document.body
|
config.target = getElement(config.target) || document.body
|
||||||
|
|
||||||
|
// TODO: v6 Only for backwards compatibility reasons. Use rootMargin only
|
||||||
|
config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin
|
||||||
|
|
||||||
|
if (typeof config.threshold === 'string') {
|
||||||
|
config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))
|
||||||
|
}
|
||||||
|
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,8 +150,8 @@ class ScrollSpy extends BaseComponent {
|
|||||||
_getNewObserver() {
|
_getNewObserver() {
|
||||||
const options = {
|
const options = {
|
||||||
root: this._rootElement,
|
root: this._rootElement,
|
||||||
threshold: [0.1, 0.5, 1],
|
threshold: this._config.threshold,
|
||||||
rootMargin: this._getRootMargin()
|
rootMargin: this._config.rootMargin
|
||||||
}
|
}
|
||||||
|
|
||||||
return new IntersectionObserver(entries => this._observerCallback(entries), options)
|
return new IntersectionObserver(entries => this._observerCallback(entries), options)
|
||||||
@@ -187,11 +196,6 @@ class ScrollSpy extends BaseComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: v6 Only for backwards compatibility reasons. Use rootMargin only
|
|
||||||
_getRootMargin() {
|
|
||||||
return this._config.offset ? `${this._config.offset}px 0px -30%` : this._config.rootMargin
|
|
||||||
}
|
|
||||||
|
|
||||||
_initializeTargetsAndObservables() {
|
_initializeTargetsAndObservables() {
|
||||||
this._targetLinks = new Map()
|
this._targetLinks = new Map()
|
||||||
this._observableSections = new Map()
|
this._observableSections = new Map()
|
||||||
|
@@ -126,6 +126,50 @@ describe('ScrollSpy', () => {
|
|||||||
expect(scrollSpy._rootElement).toBeNull()
|
expect(scrollSpy._rootElement).toBeNull()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should respect threshold option', () => {
|
||||||
|
fixtureEl.innerHTML = [
|
||||||
|
'<ul id="navigation" class="navbar">',
|
||||||
|
' <a class="nav-link active" id="one-link" href="#">One</a>' +
|
||||||
|
'</ul>',
|
||||||
|
'<div id="content">',
|
||||||
|
' <div id="one-link">test</div>',
|
||||||
|
'</div>'
|
||||||
|
].join('')
|
||||||
|
|
||||||
|
const scrollSpy = new ScrollSpy('#content', {
|
||||||
|
target: '#navigation',
|
||||||
|
threshold: [1]
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(scrollSpy._observer.thresholds).toEqual([1])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respect threshold option markup', () => {
|
||||||
|
fixtureEl.innerHTML = [
|
||||||
|
'<ul id="navigation" class="navbar">',
|
||||||
|
' <a class="nav-link active" id="one-link" href="#">One</a>' +
|
||||||
|
'</ul>',
|
||||||
|
'<div id="content" data-bs-threshold="0,0.2,1">',
|
||||||
|
' <div id="one-link">test</div>',
|
||||||
|
'</div>'
|
||||||
|
].join('')
|
||||||
|
|
||||||
|
const scrollSpy = new ScrollSpy('#content', {
|
||||||
|
target: '#navigation'
|
||||||
|
})
|
||||||
|
|
||||||
|
// See https://stackoverflow.com/a/45592926
|
||||||
|
const expectToBeCloseToArray = (actual, expected) => {
|
||||||
|
expect(actual.length).toBe(expected.length)
|
||||||
|
for (const x of actual) {
|
||||||
|
const i = actual.indexOf(x)
|
||||||
|
expect(x).withContext(`[${i}]`).toBeCloseTo(expected[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expectToBeCloseToArray(scrollSpy._observer.thresholds, [0, 0.2, 1])
|
||||||
|
})
|
||||||
|
|
||||||
it('should not take count to not visible sections', () => {
|
it('should not take count to not visible sections', () => {
|
||||||
fixtureEl.innerHTML = [
|
fixtureEl.innerHTML = [
|
||||||
'<nav id="navigation" class="navbar">',
|
'<nav id="navigation" class="navbar">',
|
||||||
|
@@ -380,6 +380,8 @@ const scrollSpy = new bootstrap.ScrollSpy(document.body, {
|
|||||||
| `rootMargin` | string | `0px 0px -40%` | Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/rootMargin) valid units, when calculating scroll position. |
|
| `rootMargin` | string | `0px 0px -40%` | Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/rootMargin) valid units, when calculating scroll position. |
|
||||||
| `smoothScroll` | boolean | `false` | Enables smooth scrolling when a user clicks on a link that refers to ScrollSpy observables. |
|
| `smoothScroll` | boolean | `false` | Enables smooth scrolling when a user clicks on a link that refers to ScrollSpy observables. |
|
||||||
| `target` | string \| jQuery object \| DOM element | | Specifies element to apply Scrollspy plugin. |
|
| `target` | string \| jQuery object \| DOM element | | Specifies element to apply Scrollspy plugin. |
|
||||||
|
| `threshold` | array | `[0.1, 0.5, 1]` | `IntersectionObserver` [threshold](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver#threshold) valid input, when calculating scroll position.|
|
||||||
|
|
||||||
{{< /bs-table >}}
|
{{< /bs-table >}}
|
||||||
|
|
||||||
{{< callout warning >}}
|
{{< callout warning >}}
|
||||||
|
Reference in New Issue
Block a user