質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.23%

Vue.jsで戻るを押したときにスクロールさせたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 3,726

aglkjggg

score 740

 前提

  • 環境準備方法
$ vue init webpack my-project
$ cd my-project
$ npm install
$ npm run dev
  • Vue.js で下記2つの画面を用意しています。
  1. ユーザー一覧 (Users)
  2. ユーザー詳細 (UserDetail)

 問題点

「戻る」を押したときに常に一番上に戻ってしまいます。

 聞きたいこと

常に前のページのスクロール位置を記憶してその場所にスクロールさせたいです。

 試したこと

  • scrollBehavior を実装した。

→ scrollBehavior が呼ばれない為効果がなかった。

 ソースコード

  • /my-project/src/main.js
import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App }
})
  • /my-project/src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import Users from '@/components/Users'
import UserDetail from '@/components/UserDetail'

Vue.use(Router)

export default new Router({
  routes: [
    { path: '/users', name: 'Users', component: Users },
    { path: '/user/:id', name: 'UserDetail', component: UserDetail }
  ],
  scrollBehavior (to, from, savedPosition) {
    console.log('scroll behavior')
    if (savedPosition) {
      console.log(savedPosition)
      return savedPosition
    } else {
      return { x: 0, y: 0 }
    }
  }
})
  • /my-project/src/App.vue
<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'app'
}
</script>
  • /my-project/src/components/Users.vue
<template>
  <div class="users">
    <ul v-for="user in users" :key="user.id">
      <li><router-link :to="'/user/' + user.id">{{user.name}}</router-link></li>
    </ul>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: 'users',
  data () {
    return {
      users: null
    }
  },
  methods: {
    getUsers () {
      var url = 'https://gist.githubusercontent.com/anonymous/f40a3124bf4885a6a97fe6506043e582/raw/32f3edb1239d5b806d586bbf9035138cdb73c401/users.json'
      axios.get(url).then(x => { this.users = x.data })
    }
  },
  mounted () {
    this.getUsers()
  }
}
</script>
  • /my-project/src/components/UserDetail.vue
<template>
  <div class="userDetail">
    <h1>ユーザー詳細</h1>
  </div>
</template>

<script>
export default {
  name: 'userDetial'
}
</script>
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

+1

 3点の問題がありました。

 1. mode: 'history' でしか動かない

注意: この機能は HTML5 history モードでのみ動作します。


(以下の記事から抜粋)
https://router.vuejs.org/ja/advanced/scroll-behavior.html

つまり、/my-project/src/router/index.js を以下のようにする必要がありました。

export default new Router({
  routes: [ ... ],
  mode: 'history',
})


また、HTML5 history モードにするとURLが
http://127.0.0.1:8080/#/users
から
http://127.0.0.1:8080/users
に変化します。

また、HTML5 history モードにするとWebサーバ側での設定が必要になります。
下記のドキュメントに詳細が書いてあります。
https://router.vuejs.org/ja/essentials/history-mode.html

 2. usersが開かれるたびにJSONデータを取りに行っていた点

/my-project/src/main.js で一度だけJSONを取りに行きその後は再利用する必要がありました。
そもそもコンポーネントでデータを取りに行くのは良くないみたいです。

 3. x = 1にする必要がある

savedPosition.x = 1にするとうまくいきました。
yを変えてもダメでした。
1じゃなくても10でも20でも519521のような適当な数でもOKでした。
なぜうまくいくのかは謎です…。
この savedPosition.x= 1 が不要なケースも有りました。謎です…。

scrollBehavior (to, from, savedPosition) {
  console.log('scroll behavior')
  if (savedPosition) {
    savedPosition.x = 1
    return savedPosition
  } else {
    return { x: 0, y: 0 }
  }
}

 変えたソースコード

  • /my-project/src/main.js
import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

import axios from 'axios'

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App },
  data () {
    return {
      users: null
    }
  },
  methods: {
    getUsers () {
      var url = 'https://gist.githubusercontent.com/anonymous/f40a3124bf4885a6a97fe6506043e582/raw/32f3edb1239d5b806d586bbf9035138cdb73c401/users.json'
      axios.get(url).then(x => { this.users = x.data })
    }
  },
  mounted () {
    this.getUsers()
  }
})
  • /my-project/src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import Users from '@/components/Users'
import UserDetail from '@/components/UserDetail'

Vue.use(Router)

export default new Router({
  routes: [
    { path: '/users', name: 'Users', component: Users },
    { path: '/user/:id', name: 'UserDetail', component: UserDetail }
  ],
  mode: 'history',
  scrollBehavior (to, from, savedPosition) {
    console.log('scroll behavior')
    if (savedPosition) {
      savedPosition.x = 1
      return savedPosition
    } else {
      return { x: 0, y: 0 }
    }
  }
})
  • /my-project/src/App.vue
    変更なし

  • /my-project/src/components/Users.vue

<template>
  <div class="users">
    <div v-if="this.$parent.$parent.$data.users != null">
      <ul v-for="user in this.$parent.$parent.$data.users" :key="user.id">
        <li><router-link :to="'/user/' + user.id">{{user.name}}</router-link></li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  name: 'users'
}
</script>
  • /my-project/src/components/UserDetail.vue
    変更なし

 参考

http://notsleeeping.com/archives/2676

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/10 23:49

    1年ほどたち、ある程度Vueを利用したので追記します。
    1.一番の問題は2でした。データ取得が完了するまで要素が無い為スクロールバーも消えて常に一番上にスクロールされたかのような動きになっていました。
    2. 1が問題なので、scrollBehaviorを利用する必要はありませんでした。
    3. this.$parent.$parent.$data.usersという書き方は見づらい。最悪。何個$parentを書いたか分からなくなる。
    4. root要素はthis.$root.usersでアクセスできる。
    5. そもそもroot要素にデータを置くのは良くない。StoreパターンやVuexを使うべき。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.23%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る