owned mediaウェブ制作に役立つコンテンツを発信中!

Vue.jsでスクロールに連動したコンテンツナビゲーションを実装する

1枚もののウェブページで表示されているコンテンツに合わせてメニューのナビゲーションが変わるというような機能要件をVue.jsで実装してみたいと思います。このような機能は以前にもjQueryで実装したまとめ(「jQueryでスクロールと連動したコンテンツナビゲーションを実装する」)にて紹介していましたが、Vue.jsではもっとわかりやすく、また双方向バインディングでテンプレート側の切り分けも簡単にできるのでこちらの方がオススメですね。   それでは早速コードを見ていきます。まずはHTMLです、今回はサンプル用としてセクションをいくつか用意し、ヘッダー部分にセクションに対応した現在のコンテンツ名を出力する部分を設けました。その部分はVue.js側で返ってきた値をそのまま表示させるためマスタッシュ記法で記述しておきます。 【HTML(Pug)】※一部抜粋
div#app
  header
    span.
      {{ currentNavi }}
  main
    section(id="section_01")
      span コンテンツ1のエリアです
    section(id="section_02")
      span コンテンツ2のエリアです
    section(id="section_03")
      span コンテンツ3のエリアです
    section(id="section_04")
      span コンテンツ4のエリアです
    section(id="section_05")
      span コンテンツ5のエリアです
  続いて処理の部分です。今回はVue.jsで新たにインスタンスを作成する方法でまとめていますが、単一コンポーネントを使う場合でも同じになります。まずはdataオプションに格納する値を変数として持たせておきます。ここでは縦方向のスクロール量と対象となるセクションのページトップからのY座標を配列で持たせるようにします。   computedのオプションでは、現在のスクロール量からどのコンテンツの位置にいるかを調べて、条件分岐させて対象となるコンテンツ名を返すようにしています。今回はこの値をそのままテンプレートに出力しています。 【JavaScript(Vue)】
var vueModel = new Vue({
  el: '#app',
  data() {
    return {
      scrollY: 0,
      sectionOffsetTop: []
    }
  },
  computed: {
    currentNavi() {
      if(this.scrollY >= this.sectionOffsetTop[0] && this.scrollY < this.sectionOffsetTop[1]) {
        return 'コンテンツ1'
      } else if(this.scrollY >= this.sectionOffsetTop[1] && this.scrollY < this.sectionOffsetTop[2]) {
        return 'コンテンツ2'
      } else if(this.scrollY >= this.sectionOffsetTop[2] && this.scrollY < this.sectionOffsetTop[3]) {
        return 'コンテンツ3'
      } else if(this.scrollY >= this.sectionOffsetTop[3] && this.scrollY < this.sectionOffsetTop[4]) {
        return 'コンテンツ4'
      } else if(this.scrollY >= this.sectionOffsetTop[4]) {
        return 'コンテンツ5'
      } else {
        return 'スクロールすると現在のコンテンツ名が表示されます'
      }
    }
  },
  mounted() {
    window.addEventListener('scroll', () => {
      this.pushScrollY();
    });
    window.addEventListener('resize', () => {
      this.pushScrollY();
    });
    this.pushElementOffsetTop();
  },
  methods: {
    pushScrollY() {
      this.scrollY = window.scrollY;
    },
    pushElementOffsetTop() {
      const targets = [
        'section_01', 'section_02', 'section_03', 'section_04', 'section_05'
      ];
      targets.forEach(target => {
        const element = document.getElementById(target);
        const offsetTop = Math.round(window.scrollY + element.getBoundingClientRect().top);
        this.sectionOffsetTop.push(offsetTop);
      });
    }
  }
});
  続いてmethodsオプションでは今回の機能に必要となる処理を定義しています。ここで必要になるのは「現在のスクロール量を取得」する処理と「各セクションのページトップからのY座標を取得」する処理の2つになります。Y座標を取得する処理は「getBoundingClientRect().top」で取得できますが、スクロール分を考慮しないといけないのと、小数点が発生した場合の対応も忘れず行なっておきます。最後に、DOMを操作することになるのでmountedオプションで定義した処理を実行するようにしておきます。createdオプションで実行した場合にはDOMが取得できないのでundefinedが返ってきてしまいます。   これでスクロールに合わせたコンテンツナビゲーションが作成できました。今回のサンプルはこちらにあげておりますので、ぜひご参考ください。

See the Pen contents_navi_on_vue by designsupply (@designsupply) on CodePen.

 
  同じ機能でもjQueryではコードが複雑になりがちですが、Vue.jsを使うことでかなり見通しが良くなりました。カスタマイズするときも楽ですね。またHTMLのテンプレート側にも処理に合わせて動的に値を出力したりすることもできますので、より高度な見せ方も可能になりますね。1枚もののページを作成する場合にはぜひ試してみてはいかがでしょうか。  
  • はてなブックマーク
  • Pocket
  • Linkedin
  • Feedly

この記事を書いた人

Twitter

sponserd

    keyword search

    recent posts

    • Twitter
    • Github
    contact usscroll to top
      • Facebook
      • Twitter
      • Github
      • Instagram