JavaScript multifunctional smooth scrolling SVG support
JavaScript multifunctional smooth scrolling SVG support
Category:JavaScript
Pub.date:2022-01-06
I've been writing JavaScript for smooth scrolling for a long time, but I've rewritten it to organize it.
The code is long, but it's the result of extending it to handle various situations.
Of course, it doesn't use jQuery. It works by itself.
The features and functions are as follows:
- It works just by installing it alone.
- Scrollable to anchor tags in inline SVG.
- Dynamic anchor tag placement is also supported.
- Scrolling is possible by directly specifying the anchor tag.
- Directly specify an ID name to scroll.
- Direct scrolling by specifying a numerical value for the scroll position.
- Directly specify an element to scroll.
- Scroll speed can be set.
- Scroll position can be adjusted. If the header is 100px long, it can be moved by 100px.
- etc.
It will continue to expand with the times.
/**
* スムーススクロール インラインSVG内アンカータグ対応
*
* usage:
* <script src="smoothscroll.js"></script> //このファイル
* 以下、必要に応じて:
* <script> SmoothScroll.setOption({offset:-200}); </script> //オフセット位置設定(スクロール位置をずらす)
* <script> SmoothScroll.setOption({speed:20}); </script> //速度設定
* <script> SmoothScroll.reInit(); </script> //動的に要素を追加したときに再スキャン
* <script> SmoothScroll.addRender(elm); </script> //aタグを動的に追加した場合にイベントリスナー追加
* <script> SmoothScroll.elementScroll(elm); </script> //エレメントへスクロール
* <script> SmoothScroll.anchorScroll('anchorName'); </script> //ページ読み込み後にアンカー名へスクロール
* <script> SmoothScroll.nameScroll('anchorName'); </script> //アンカー名へスクロール
* <script> SmoothScroll.idScroll('idName'); </script> //id名へスクロール
* <script> SmoothScroll.positionScroll(800); </script> //数値指定でスクロール
*
* @author ao-system, Inc.
*
* @date 2015.04.26
* @date 2017.07.25
* @date 2017.09.22
* @date 2017.10.03
* @date 2018.06.20
* @date 2018.09.11
* @date 2019.07.18
* @date 2021.01.19
* @date 2022.01.06
*/
'use strict';
const SmoothScroll = {
_speed: 10,
_offset: 0,
_lastPos: 0,
_interval: 0,
_direction: '',
//要素の位置を返す
offsettop: (elm) => {
let offsettop = elm.offsetTop;
if (elm.offsetParent) {
while (elm = elm.offsetParent) {
offsettop += elm.offsetTop;
}
}
return Math.max(0, offsettop + SmoothScroll._offset);
},
//スクロール位置を返す
scrolltop: () => {
if (document.body && document.body.scrollTop) {
return document.body.scrollTop;
}
if (document.documentElement && document.documentElement.scrollTop) {
return document.documentElement.scrollTop;
}
if (window.pageYOffset) {
return window.pageYOffset;
}
return 0;
},
//イベントをキャンセルする
killEvt: (evt) => {
if (evt.preventDefault && evt.stopPropagation) {
evt.preventDefault();
evt.stopPropagation();
} else {
evt.cancelBubble = true;
evt.returnValue = false;
}
},
//目的地へスクロール
positionScroll: (targetPos) => {
let currentPos = SmoothScroll.scrolltop(); //現在の位置
if (SmoothScroll._direction == '') { //初回に移動方向を記録
SmoothScroll._direction = targetPos > currentPos ? 'plus' : 'minus';
}
let moveSize = Math.ceil((targetPos - currentPos) / SmoothScroll._speed);
if (moveSize == 0) { //目的地まで達する様に調整
moveSize = targetPos > currentPos ? 1 : -1;
}
currentPos += moveSize;
window.scrollTo(0,currentPos);
if (currentPos == targetPos || SmoothScroll._lastPos == currentPos) { //目的地に達したか、動けなくなったか
clearInterval(SmoothScroll._interval);
SmoothScroll._direction = '';
window.scrollTo(0,targetPos);
}
if ((SmoothScroll._direction == 'plus' && targetPos < currentPos) || (SmoothScroll._direction == 'minus' && targetPos > currentPos)) { //移動方向に矛盾が生じた場合
clearInterval(SmoothScroll._interval);
SmoothScroll._direction = '';
window.scrollTo(0,targetPos);
}
SmoothScroll._lastPos = currentPos;
},
//クリック時のイベント
renderClick: (evt) => {
SmoothScroll.killEvt(evt);
let href = evt.target.href || evt.target.parentNode.href || evt.target.parentNode.parentNode.href || evt.target.parentNode.parentNode.parentNode.href || evt.target.parentNode.parentNode.parentNode.parentNode.href || null;
let hash = evt.target.hash || evt.target.parentNode.hash || evt.target.parentNode.parentNode.hash || evt.target.parentNode.parentNode.parentNode.hash || evt.target.parentNode.parentNode.parentNode.parentNode.hash || null;
let anchorTagName = '';
if (href && href.baseVal) { //SVGの場合 e.g. <svg><a href="#footer"><rect .. /></a></svg>
anchorTagName = href.baseVal.substr(1);
} else if (hash) {
anchorTagName = hash.substr(1);
} else {
return;
}
const anchorTags = document.getElementsByTagName('a');
Array.prototype.forEach.call(anchorTags,(anchorTag) => {
if (anchorTag.name == anchorTagName) {
clearInterval(SmoothScroll._interval);
((anchorTag) => {
SmoothScroll.elementScroll(anchorTag);
})(anchorTag);
}
});
},
//イベントリスナー用意
render: () => {
const anchorTags = document.getElementsByTagName('a');
Array.prototype.forEach.call(anchorTags,(anchorTag) => {
if (anchorTag.href) {
if (anchorTag.href.baseVal) { //SVGの場合 e.g. <svg><a href="#footer"><rect .. /></a></svg>
if (anchorTag.href.baseVal.substr(0,1) == '#') {
((elm) => {
elm.removeEventListener('click',SmoothScroll.renderClick);
elm.addEventListener('click',SmoothScroll.renderClick);
})(anchorTag);
}
} else {
if (anchorTag.href.indexOf('#') != -1 && ((anchorTag.pathname == location.pathname) || ('/' + anchorTag.pathname == location.pathname))) {
((elm) => {
elm.removeEventListener('click',SmoothScroll.renderClick);
elm.addEventListener('click',SmoothScroll.renderClick);
})(anchorTag);
}
}
}
});
},
//オプション設定
setOption: (obj) => {
if (obj.offset) {
SmoothScroll._offset = obj.offset; //スクロール位置のオフセット
}
if (obj.speed) {
SmoothScroll._speed = obj.speed; //速度設定
}
},
//初期設定
init: () => {
window.addEventListener('load',SmoothScroll.render);
},
//初期設定 再度
reInit: () => {
SmoothScroll.render();
},
//イベントリスナー 後から個別に追加
addRender: (anchorElm) => {
if (anchorElm.href) {
if (anchorElm.href.baseVal) { //SVGの場合 e.g. <svg><a href="#footer"><rect .. /></a></svg>
if (anchorElm.href.baseVal.substr(0,1) == '#') {
anchorElm.removeEventListener('click',SmoothScroll.renderClick);
anchorElm.addEventListener('click',SmoothScroll.renderClick);
}
} else {
if (anchorElm.href.indexOf('#') != -1 && ((anchorElm.pathname == location.pathname) || ('/' + anchorElm.pathname == location.pathname))) {
anchorElm.removeEventListener('click',SmoothScroll.renderClick);
anchorElm.addEventListener('click',SmoothScroll.renderClick);
}
}
}
},
//elementへスクロール
elementScroll: (elm) => {
if (elm) {
SmoothScroll._interval = setInterval(() => {SmoothScroll.positionScroll(SmoothScroll.offsettop(elm))},10);
}
},
//アンカー名へスクロールする Load時にセット
anchorScroll: (nameValue) => {
window.addEventListener('load',() => {
if (document.getElementById('loading')) { //ページロード中表示があればそれを消す
document.getElementById('loading').outerHTML = '';
}
SmoothScroll.elementScroll(document.getElementsByName(nameValue).item(0));
});
},
//name名へスクロールする。ダイレクト実行
nameScroll: (nameValue) => {
SmoothScroll.elementScroll(document.getElementsByName(nameValue).item(0));
},
//ID名へスクロールする。ダイレクト実行
idScroll: (idValue) => {
SmoothScroll.elementScroll(document.getElementById(idValue));
},
};
SmoothScroll.init();
CONTENTS
JavaScript
Unreal Engine
CakePHP4
CakePHP4
Flutter
Flutter
Other
JavaScript
JavaScript
CakePHP4
Web Server
Photoshop
Unreal Engine
CakePHP4
Web Browser
Web Server
iOS
Android
Web Browser
CakePHP4
Plesk
Illustrator
Plesk
Web Server
Web Server
CakePHP3
Web Browser
CakePHP3
JavaScript
JavaScript
CakePHP3
CakePHP3