Last active
March 23, 2022 07:28
-
-
Save suinua/193d697b27deff9ca4f8f4982776b645 to your computer and use it in GitHub Desktop.
Dartでスクロールに連動する目次
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <link rel="stylesheet" href="styles.css"> | |
| <script defer src="main.dart.js"></script> | |
| </head> | |
| <body> | |
| <div class="wrap"> | |
| <div class="left"> | |
| <h1 id="Fruit">Fruit</h1> | |
| <div class="box"></div> | |
| <h2 id="Apple">Apple</h2> | |
| <div class="box"></div> | |
| <h2 id="Banana">Banana</h2> | |
| <div class="box"></div> | |
| <div class="box"></div> | |
| <h1 id="Vegetable">Vegetable</h1> | |
| <div class="box"></div> | |
| <h2 id="Potato">Potato</h2> | |
| <div class="box"></div> | |
| <div class="box"></div> | |
| <h2 id="Eggplant">Eggplant</h2> | |
| <div class="box"></div> | |
| <div class="box"></div> | |
| <div class="box"></div> | |
| <div class="box"></div> | |
| </div> | |
| <div class="right"> | |
| <div class="toc"> | |
| <a class="toc-item" target-id="Fruit">Fruit</a> | |
| <a class="toc-item" target-id="Apple">Apple</a> | |
| <a class="toc-item" target-id="Banana">Banana</a> | |
| <a class="toc-item" target-id="Vegetable">Vegetable</a> | |
| <a class="toc-item" target-id="Potato">Potato</a> | |
| <a class="toc-item" target-id="Eggplant">Eggplant</a> | |
| </div> | |
| </div> | |
| </div> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'dart:html'; | |
| void main() { | |
| var separatingElements = <Element>[]; | |
| //今回は<h1>と<h2> | |
| separatingElements.addAll(querySelectorAll('h1')); | |
| separatingElements.addAll(querySelectorAll('h2')); | |
| var tocItems = | |
| querySelectorAll('.toc-item').whereType<AnchorElement>().toList(); | |
| //スクロール時 | |
| document.onScroll.listen((event) { | |
| var nearbyElement = getNearbyElement(separatingElements); | |
| activeTocItem(tocItems, nearbyElement.id); | |
| }); | |
| //tocクリック時 | |
| tocItems.forEach((tocItem) { | |
| tocItem.onClick.listen((event) async { | |
| var id = tocItem.getAttribute('target-id')!; | |
| var target = document.getElementById(id)!; | |
| window | |
| .scrollTo({'top': target.offsetTop, 'left': 0, 'behavior': 'smooth'}); | |
| }); | |
| }); | |
| } | |
| Element getNearbyElement(List<Element> elements) { | |
| const topDetection = 50; | |
| Element? result; | |
| for (var i = 0; i < elements.length; i++) { | |
| var element = elements[i]; | |
| if (result == null) { | |
| result = element; | |
| continue; | |
| } | |
| //要素とスクロール地点の差 | |
| var diff = element.offsetTop - window.scrollY; | |
| //resultとスクロール地点の差 | |
| var resultDiff = result.offsetTop - window.scrollY; | |
| if (0 < diff && diff < topDetection) return element; | |
| /** | |
| * Element | |
| * | |
| * | |
| * | |
| * | |
| * | |
| * -------スクロール位置---- | |
| * ↑ | |
| * 50px(topDetection) | |
| * ↓ | |
| * Element(目次に表示させるのはコイツ) | |
| */ | |
| //スクロール地点より下にあったら除外, | |
| /** | |
| * Element(目次に表示させるのはコイツ) | |
| * | |
| * -------スクロール位置---- | |
| *↑ | |
| *50px(topDetection)オーバー | |
| *↓ | |
| * Element 除外 | |
| * | |
| * | |
| * Element 除外 | |
| */ | |
| if (diff > 0) continue; | |
| //スクロール地点との差がより小さければresultに代入 | |
| if (diff.abs() < resultDiff.abs()) result = element; | |
| } | |
| return result!; | |
| } | |
| void activeTocItem(List<AnchorElement> tocItems, String separatingElementId) { | |
| tocItems.forEach((tocItem) { | |
| var targetId = tocItem.getAttribute('target-id')!; | |
| if (targetId == separatingElementId) { | |
| //activeクラスを付与 | |
| tocItem.classes.add('active'); | |
| } else { | |
| //activeクラスを除去 | |
| tocItem.classes.removeWhere((element) => element == 'active'); | |
| } | |
| }); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| html, body { | |
| width: 100%; | |
| height: 100%; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| .wrap { | |
| display: flex; | |
| } | |
| .left { | |
| width: 80%; | |
| } | |
| .right { | |
| width: 20%; | |
| } | |
| .toc { | |
| position: sticky; | |
| top: 20px; | |
| } | |
| .toc-item { | |
| display: block; | |
| color: white; | |
| } | |
| .active { | |
| color: pink; | |
| } | |
| .box { | |
| height: 300px; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment