開発者ドキュメント

Vue.jsを使用したコンテンツプレースホルダー戦略の調査

最近大きな注目を集めているのは、コンテンツ全体が読み込まれる前に、完全に読み込まれたページのように見えるプレースホルダースタイルでいっぱいのUIを表示することです。 この戦術は、 Slack Medium Facebook などで使用されており、ページの読み込み中に予期しないジャンプを回避し、ユーザーに感じさせるのに役立ちます。ページの読み込みが速くなっているようです。 Vue.js を使用すると、これを簡単に実現できます。 ここでは、これを行うためのいくつかの方法について説明します。

空ですか?

最も基本的な方法は、空の要素とコンテンツのある要素に異なるスタイルを設定することです。 まあ、あなたは実際にプレーンCSSでそれを行うことができます。

<template>
  <p class="has-placeholder">{{content}}</p>
</template>

...

<style>
.has-placeholder {
  filter: none;
  transition: all 200ms;
  background-color: transparent;
}

.has-placeholder:empty {
  width: 5vw;
  height: 20px;
  background-color: rgba(0, 0, 0, 0.2);
  filter: blur(7px);
}
</style>

かなりうまくいきますね! ただし、現在定義されていないオブジェクトのプロパティなど、存在しない可能性のある値ではうまく機能しません。

さらに悪いことに、:empty 疑似セレクターは、ソースに空白がなく、完全に空の要素にのみ一致します。 つまり、複数行または間隔のある要素がないことを意味します。

<p></p> <!-- Empty -->
<p> </p> <!-- Not Empty -->
<p>
</p> <!-- Not Empty -->

そこで、次の方法を試してみます。

上品なトグル

Vueを使用してクラスを切り替えるのは、前の方法とほぼ同じくらい簡単であり、複数行のタグを使用できるようにするという追加のボーナスがあります。

<template>
  <p class="has-placeholder" :class="{empty: !content}">
    {{content}}
  </p>
</template>

...

<style>
.has-placeholder {
  filter: none;
  transition: all 200ms;
  background-color: transparent;
}

.has-placeholder.empty {
  width: 5vw;
  height: 20px;
  background-color: rgba(0, 0, 0, 0.2);
  filter: blur(7px);
}
</style>

ただし、これにはまだオブジェクトに存在しない可能性のある値にアクセスするという問題があり、それはそれほど慣用的なものではないため、さらに深く掘り下げる必要があります。

条件付きコンテンツ

これはおそらく、この種の問題に対処しようとするときに頭に浮かぶかもしれない最初の解決策です。 単純に2つの実行パスがあります。1つはデータのロード時用で、もう1つはプレースホルダー用です。

<template>
  <div class="wrapper">
    <p v-if="content">
      {{content}}
    </p>
    <p v-else class="has-placeholder empty"></p>
  </div>
</template>

...

<style>
.has-placeholder.empty {
  width: 5vw;
  height: 20px;
  background-color: rgba(0, 0, 0, 0.2);
  filter: blur(7px);
}
</style>

残念ながら、この方法では、冗長性が増し、パフォーマンスが低下し、プロセスの遷移が失われます。 コードは非常に明示的ですが、かなり乱雑に見えます。 また、レイアウト全体を2つのパスに分割しない限り、すべてのプロパティに条件を導入する必要があります…

重複したレイアウト

…これが私たちが今やろうとしていることです! この方法には、はるかに冗長で保守が難しい可能性があるという欠点がありますが、多くのカスタマイズと非常に単純な使用法も可能になります。

<template>
  <div class="wrapper">
    <!-- Render the live template -->
    <div v-if="contentObject" class="user-container">
      <img class="avatar" :src="contentObject.avatar"/>
      <h2>My Name is {{contentObject.name}}</h2>
      <h4>Biography</h4>
      <p>{{contentObject.bio}}</p>
    </div>

    <!-- Render the placeholder template -->
    <div v-else class="user-container placeholder">
      <img class="avatar" src="/path/to/default-avatar.png"/>
      <h2></h2>
      <h4>Biography</h4>
      <p></p>
    </div>
  </div>
</template>

...


<style>
.user-container.placeholder > *:not(img) {
  background-color: rgba(0, 0, 0, 0.2);
  filter: blur(7px);
}

.user-container.placeholder h2 {
  height: 40px;
  width: 50%;
}

.user-container.placeholder p {
  height: 400px;
  width: 30%;
}
</style>

いくつかのトランジションをスローして少しクリーンアップすると、サイトでかなり実行可能なソリューションが得られます。 ただ、本当にいいものではありません。

モックデータ

私の個人的なお気に入りの解決策は、実際のデータをロードする前に、 ClassyTogglesメソッドをいくつかのモックデータと組み合わせることです。 そうすれば、無効なデータの可能性についてそれほど心配する必要がなく、保守がかなり簡単なコンポーネントを使用できます。 (つまり、モックデータをチェックすると仮定します。)

例として、このスキーマを使用します。

const person:Object = {
  name: String,
  avatar: String,
  bio: String
};

const people: Array<person>;
<template>
  <div class="user-container">
    <img class="avatar" :src="contentObject.avatar"/>
    <h2 :class="{placeholder: !contentObject.name}">My Name is {{contentObject.name}}</h2>

    <h4>Biography</h4>
    <p :class="{placeholder: !contentObject.bio}">
      {{contentObject.bio}}
    </p>
  </div>
</template>

<script>
export default {
  props: {
    contentObject: {
      type: Object,
      default: {
        avatar: '/path/to/default/avatar.png',
        name: '',
        bio: ''
      }
    }
  }
}
</script>

<style>
.user-container * {
  transition: all 200ms;
  background-color: transparent;
  color: inherit;
  filter: none;
}

.user-container .placeholder {
  color: transparent;
  background-color: rgba(0, 0, 0, 0.2);
  filter: blur(7px);
}

.user-container h2.placeholder {
  height: 40px;
  width: 50%;
}

.user-container p.placeholder {
  height: 400px;
  width: 30%;
}

</style>

この方法には、かなり単純なテンプレートがあり、CSSトランジションがあり、適切なデータモデルを維持できるという利点があります(ただし、より多くのチェックが必要です)。 ただし、奇妙なことが何も起こらないようにするために、テンプレートとデータモデルをしっかりと監視する必要があります。

「未定義のプロパティxを読み取れません」の回避

ほとんどすべての新しいVue.js開発者を悩ませている典型的なエラーは、まだ初期化されていないオブジェクトのプロパティにアクセスしようとするエラーです。 Angular 2+とは異なり、Vueには ?. prop?[prop] 存在演算子がないため、存在しない可能性のあるオブジェクトのプロパティにアクセスするための簡単で安全な方法はありません。

回避策として、レベルを再帰的にチェックして有効かどうかを確認するコンポーネントメソッドを使用できます。 Lo-dashには_。getメソッドが付属しています。または、多くのソリューションここのいずれかを使用できます。

ただし、より良い解決策は、一貫性のあるモデルを維持することです。 多くの場合、プロパティが存在する場合と存在しない場合は、通常、コードの臭いの兆候です。 さらに、Vueの反応性システムは、以前は存在しなかった突然存在するプロパティを取得するのが得意ではありません。

モバイルバージョンを終了