LoginSignup
13
8

More than 5 years have passed since last update.

【コードの隠し味】あなたのコードは大丈夫??一瞬のUI崩れをVue.js templateタグが解決してくれる。

Last updated at Posted at 2018-11-07

記事タイトルがターゲットニッチすぎて見つけられないことは承知の上、この現象を紹介します。

まずはこちらのサイトの動きを見てください。(1度リロードしています)

Image from Gyazo

こちらのページでは、SNSボタン付近が読み込まれる時、ローディング後(今回はリロード後)に、画面が少し下がってからSNSボタンが表示されます。
このような少し不自然なガクッとなる状況を、Vue.jsのtemplateタグを使って、解決しようと思います。

ガクッとなる原因のコードは?

まずは、このガクッとなる部分で何が起きているのか見ていきます。
デベロッパーツールで確認してみると、このような構成になっていました。

template.png

SNSボタン表示後のスタイルを見ると、周りに画像のような margin がみられます。
これはHTMLのコードで書いてみれば下記のような感じです。

<!-- html -->
<div v-if="SNSボタンがあれば" class="sns-wrap">
  <div class="sns-wrap__btn">シェア</div>
</div>
<NotfoundBlock v-else-if="SNSボタンがなければ(*1)"/>
<LoadingBlock v-else="SNSボタンを読み込み中(*2)" />
.sns-wrap {
  &__btn {
    margin: 10px 20px 10px 0;
  }
}

NotfoundBlock(データが取得できない)とLoadingBlock(ローディング中のクルクル)は独自のコンポーネントです。

上記のようなコードの場合処理の順番は
1. <~ class="sns-wrap"> のloading中だとLoadingBlockが呼ばれる。
2. そのあとloadされた<~class="sns-wrap">が出てくる。
このときLoadingBlock<~ class="sns-wrap">の大きさの差(sns-wrapにmarginが付いているため)でガクッと表示されているように見える。

です。

ガクッと潰れてしまう問題を解決したいので、こんな解決策が思いついたので試してみます。

安直な解決策(間違い)

marginを指定しているdivの中に書くことで、読み込みがされている最中にもmarginが適用され、ガクッとなる問題は解決するのでは(?)と思い、NotfoundBlockLoadingBlockのコンポーネントを、marginをつけている divの中に入れてみました。(これは間違いです)

<div v-if="SNSボタンがあれば" class="sns-wrap">
  <div class="sns-wrap__btn">シェア</div>
  <NotfoundBlock v-else-if="SNSボタンがなければ"/>
  <LoadingBlock v-else="SNSボタンを読み込み中" />
</div>

v-if の直下に v-else, v-else-if が配置されています。しかし、この3つは本来並列に配置されるものなので、そもそも書き方が間違っているため、このコードでは正しくありません。

正しい解決策

v-if , v-else, v-else-if を並列に配置しながら、marginの影響化に置きたいとき、templateタグを使うことでうまくいきます。

以下のようにtemplateを使います。

<div class="sns-wrap">
  <template v-if="SNSボタンがあれば">
    <div class="sns-wrap__btn">シェア</div>
  </template>
  <NotfoundBlock v-else-if="SNSボタンがなければ"/>
  <LoadingBlock v-else="SNSボタンを読み込み中" />
</div>

このように templateを使用することで、sns-wrapのスタイル(margin)を残したまま、読み込み、読み込み中、読み込みできなかったが実装することができます。
templateタグを使えば、読み込み後に急にmarginがついてガクッとなるというような違和感のあるコードを修正することができます。

template タグの役割

template タグは、div タグのような階層をつくることなく、並列関係を保つことができます。また、classはつけられないという特徴もあります。

div タグでもいい?

div でもいいけれど、template のように本来ないタグのように扱われないので、divタグで囲った中の要素は、その上のタグの直下の影響下に置くことはできません。

下記コードにおいて、A, B, Cは並列関係にあります。

(例) template タグを使用した例

<!-- html -->
<div class="sns-wrap">
  <template v-if="SNSボタンがあれば">
    <div class="sns-wrap__btn">シェア</div> // A
  </template>
  <NotfoundBlock v-else-if="SNSボタンがなければ"/> // B
  <LoadingBlock v-else="SNSボタンを読み込み中" /> // C
</div>

(例) div タグを使用した例

<!-- html -->
<div class="sns-wrap">
  <div v-if="SNSボタンがあれば"> // A
    <div class="sns-wrap__btn">シェア</div>
  </div>
  <NotfoundBlock v-else-if="SNSボタンがなければ"/> // B
  <LoadingBlock v-else="SNSボタンを読み込み中" /> // C
</div>

templateタグ、divタグそれぞれの効果を考えて、使用する際に使い勝手の良いものを使用するのがいいですね。

記事冒頭にも書きましたが、タイトルがターゲットニッチすぎていいねがもらえないことは承知の上、この現象を紹介しました。しかし、読んでいただいて気づかれたかもしれませんが、この現象は様々なページでよくある現象なのです。

フロントエンドエンジニアたるもの、こういった細かい知識の積み重ねが、UIを崩さない理想の開発者に繋がります。ユーザーの「なにこれ?」という違和感を生まないためにもこういった知識の積み重ねを私自身怠らないようにしたいと思います。

【緩募】
なんという検索でこちらの記事に行き着きましたか?w よければコメントで教えてくださいww

13
8
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
13
8