LoginSignup
8
1

More than 5 years have passed since last update.

Elmでページ内ジャンプをしたメモ

Last updated at Posted at 2019-03-22

結論

  • Navigation.load id

検索ワードが思い浮かばなくて、なかなか上記の結論にたどり着けませんでした。

view
 a [ onClick (PageAnchor "#some_id") ] [ text "ジャンプ!" ]

-- 省略

  div [ id "some_id"][]

update
type Msg
    = PageAnchor String

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        PageAnchor id ->
            ( model, Navigation.load id )

きっかけ

縦に長いページを作っていて、目次を作って飛べるようにしたかった。
ただ、Browser.applicationを使っていると、aタグのhrefに#idのように指定しても、
URLが変わるだけでページ内遷移しない。

失敗したパターン

https://package.elm-lang.org/packages/elm/browser/latest/Browser-Dom#setViewportOf
「Change the x and y offset of a DOM node’s viewport by ID. 」って書いてあって、
DOMの位置までスクロールしてくれるのかな、と思ったけれどそんなことはなかった。
そもそも、上のリンク先にあるサンプルコードをいれると以下のエラーがでた。


 Dom.getViewportOf id
|> Task.andThen (\info -> Dom.setViewportOf id 0 info.scene.height)
|> Task.perform (\_ -> NoOp)
 ^^^^^^^^^^^^^^^^^^^^^^^^
| The argument is:
|     Task Dom.Error ()
| But (|>) is piping it a function that expects:
|     Task Never ()

以下のように、Task.attemptに変えたら動いたけれど、なんで動かないコードが載ってるんだろう。
performが指定してあるということは、以前は失敗しなかったのかしら?

import Browser.Dom as Dom
import Task

type Msg = NoOp

jumpToBottom : String -> Cmd Msg
jumpToBottom id =
  Dom.getViewportOf id
    |> Task.andThen (\info -> Dom.setViewportOf id 0 info.scene.height)
    |> Task.attempt (\_ -> NoOp)

中途半端な成功

さて、失敗したときに、何も起こらなかったら完全にelmが動いていないのだなと思うのだけれど、
jumpToBottom id を使ったときには、新しく開いたタブに直接http://hoge/fuga#some_id と打てば、
その場所まで遷移するという動きをしていた。

助言

discordのbeginnersスレッドで困っていたら、ヤギの方が助言をくださった。

「setViewPortOf は、IDで指定した スクロール可能な 要素を任意の位置にスクロールするものであって、スクロール可能な要素に 含まれる要素 をIDで指定してその要素のところまでスクロールさせるものではないです。」

「新しいタブにURLを入れてアクセスした時は、ブラウザがハッシュ値を見てブラウザの機能でそのハッシュ値のIDを持つ要素のところまでスクロールしてるからですね!」

え、ブラウザの機能より前にelm動いてるの。意外。
もしかしたら暗黙的にNavigation.load idが呼ばれてるかもだけど。

解決

「Navigation.load "#id" を実行したら、実はページリロード無しで id 要素までスクロールしてくれたりしないでしょうか?」

Navigationってこれかー。
https://package.elm-lang.org/packages/elm/browser/latest/Browser-Navigation

すんなりうまくいきました。

補足

内部的には普通にwindow.location呼んでるんですね。
jsでどうやるかは知ってても、elmでどうやるかに応用がうまくできないなぁと。
とりあえず、このあたりの機能は Browser モジュールにないか探してみようと思いました。

https://github.com/elm/browser/blob/1.0.1/src/Elm/Kernel/Browser.js#L451
https://developer.mozilla.org/ja/docs/Web/API/Window/location

8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1