Skip to content

Commit

Permalink
feat: add smooth scroll when clicking on a menu item
Browse files Browse the repository at this point in the history
  • Loading branch information
kimyvgy committed Oct 4, 2021
1 parent e3b3642 commit 8e9aff1
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 21 deletions.
44 changes: 37 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,46 @@ scrollSpy('#main-menu', options)
```html
<script src="/path/to/dist/simple-scrollspy.min.js"></script>
<script>
window.onload = function () {
scrollSpy('#main-menu', {
sectionClass: '.scrollspy',
menuActiveTarget: '.menu-item',
offset: 100,
})
}
window.onload = function () {
scrollSpy('#main-menu', {
sectionClass: '.scrollspy',
menuActiveTarget: '.menu-item',
offset: 100,
smoothScroll: true,
})
}
</script>
```

### Smooth scroll

```javascript
import jumpTo from 'jump.js'

scrollSpy('#main-menu', {
// ....,

// enable smooth scroll:
// - true: enable with the default scroll behavior
// - false: disable this feature
// - object: enable with some options that will pass to `window.scroll` or `smoothScrollBehavior`
// + Default behavior: https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll
// + Jump.js: https://www.npmjs.com/package/jump.js
smoothScroll: {
duration: 1000, // only works with jump.js,
offset: -100, // only works with jump.js,
},

// customize scroll behavior,
// - default: window.scroll({ behavior: 'smooth', ...smoothScroll })
// - customize: you can define your scroll behavior. Ex: use `jump.js`, jQuery, .etc
smoothScrollBehavior: function(element, options) {
// use `jump.js` instead of the default scroll behavior
jumpTo(element, options)
}
})
```

## Development

```bash
Expand Down
2 changes: 1 addition & 1 deletion demo/dist/simple-scrollspy.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ <h1>
menuActiveTarget: '.menu-item',
offset: 100,
scrollContainer: '.scroll-container',
smoothScroll: true,
})
}
</script>
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@
"terser-webpack-plugin": "^2.3.1",
"webpack": "^4.4.1",
"webpack-cli": "^3.3.10"
},
"optionalDependencies": {
"jump.js": "^1.0.2"
}
}
38 changes: 36 additions & 2 deletions src/scrollspy.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ export class ScrollSpy {
hrefAttribute: 'href',
activeClass: 'active',
scrollContainer: '',
smoothScroll: {},
}

options.smoothScroll = options.smoothScroll === true && {} || options.smoothScroll

this.menuList = menu instanceof HTMLElement ? menu : document.querySelector(menu)
this.options = Object.assign({}, defaultOptions, options)

Expand All @@ -28,12 +31,30 @@ export class ScrollSpy {

this.sections = document.querySelectorAll(this.options.sectionClass)

this.listen()
this.attachEventListeners()
}

listen() {
attachEventListeners() {
if (this.scroller) {
this.scroller.addEventListener('scroll', () => this.onScroll())

// smooth scroll
if (this.options.smoothScroll) {
const menuItems = this.menuList.querySelectorAll(this.options.menuActiveTarget)
menuItems.forEach((item) => item.addEventListener('click', this.onClick.bind(this)))
}
}
}

onClick(event) {
const targetSelector = event.target.getAttribute(this.options.hrefAttribute)
const targetElement = document.querySelector(targetSelector)

if (targetElement && this.options.smoothScroll) {
// prevent click event
event.preventDefault()
// handle smooth scrolling to 'targetElement'
this.scrollTo(targetElement)
}
}

Expand All @@ -47,6 +68,19 @@ export class ScrollSpy {
}
}

scrollTo(targetElement) {
const smoothScrollBehavior = typeof this.options.smoothScrollBehavior === 'function' && this.options.smoothScrollBehavior

if (smoothScrollBehavior) {
smoothScrollBehavior(targetElement, this.options.smoothScroll)
} else {
targetElement.scrollIntoView({
...this.options.smoothScroll,
behavior: 'smooth',
})
}
}

getMenuItemBySection(section) {
if (!section) return
const sectionId = section.getAttribute('id')
Expand Down
23 changes: 12 additions & 11 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ const { resolve } = require('path')
const TerserPlugin = require('terser-webpack-plugin')

module.exports = {
entry: resolve(__dirname, 'src/index.js'),
entry: resolve(__dirname, 'src/index.js'),

output: {
path: resolve(__dirname, 'demo/dist'),
filename: 'simple-scrollspy.min.js',
library: 'scrollSpy',
libraryTarget: 'umd'
},
output: {
path: resolve(__dirname, 'demo/dist'),
filename: 'simple-scrollspy.min.js',
chunkFilename: '[name].simple-scrollspy.min.js',
library: 'scrollSpy',
libraryTarget: 'umd'
},

optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
},
optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
},
}

0 comments on commit 8e9aff1

Please sign in to comment.