使用 Vue.js 检验内容占位符策略

最近获得了相当大的吸引力的一种做法是,在整个内容加载之前显示一个用户界面充满了位置保持风格,这些风格看起来像完全加载的页面。由Slack,Medium和Facebook使用的这种策略有助于在页面加载时避免意想不到的跳跃,并使用户觉得页面加载更快。

是空的吗?

最基本的方法可能是为空的元素和具有内容的元素提供不同的风格,你实际上可以用简单的CSS来做到这一点。

 1<template>
 2  <p class="has-placeholder">{{content}}</p>
 3</template>
 4
 5...
 6
 7<style>
 8.has-placeholder {
 9  filter: none;
10  transition: all 200ms;
11  background-color: transparent;
12}
13
14.has-placeholder:empty {
15  width: 5vw;
16  height: 20px;
17  background-color: rgba(0, 0, 0, 0.2);
18  filter: blur(7px);
19}
20</style>

但是,它不适用于可能不存在的值,例如当前未定义对象的属性。

更糟糕的是:空的假选择器只匹配完全空的元素,在源中没有白空间,这意味着没有多行或甚至间隔的元素:

1<p></p> <!-- Empty -->
2<p> </p> <!-- Not Empty -->
3<p>
4</p> <!-- Not Empty -->

所以,我们会尝试下一个方法。

班级Toggles

使用Vue来转换类几乎和前一种方法一样简单,并且增加了允许我们使用多行标签的额外优惠。

 1<template>
 2  <p class="has-placeholder" :class="{empty: !content}">
 3    {{content}}
 4  </p>
 5</template>
 6
 7...
 8
 9<style>
10.has-placeholder {
11  filter: none;
12  transition: all 200ms;
13  background-color: transparent;
14}
15
16.has-placeholder.empty {
17  width: 5vw;
18  height: 20px;
19  background-color: rgba(0, 0, 0, 0.2);
20  filter: blur(7px);
21}
22</style>

然而,这仍然涉及到访问可能在对象上不存在的值的问题,而这并不是所有这些语言,所以我们需要深入研究。

条件内容

这是可能在尝试处理此类问题时想到的第一个解决方案. 简单地有两个执行路径,一个用于数据加载时,一个用于位置持有者。

 1<template>
 2  <div class="wrapper">
 3    <p v-if="content">
 4      {{content}}
 5    </p>
 6    <p v-else class="has-placeholder empty"></p>
 7  </div>
 8</template>
 9
10...
11
12<style>
13.has-placeholder.empty {
14  width: 5vw;
15  height: 20px;
16  background-color: rgba(0, 0, 0, 0.2);
17  filter: blur(7px);
18}
19</style>

不幸的是,通过这种方法,我们增加了词汇性,降低了性能,并在流程中失去了过渡。代码非常明确,但看起来相当混乱。我们还必须为每个属性引入条件,除非我们把整个布局分成两条路径...

双重布局

这是我们现在要做的事情!这种方法的缺点是,它更杂,潜在难以维护,但它还允许大量的定制和简单的使用。

 1<template>
 2  <div class="wrapper">
 3    <!-- Render the live template -->
 4    <div v-if="contentObject" class="user-container">
 5      <img class="avatar" :src="https://cdn.jsdelivr.net/gh/andsky/tutorials-images/contentObject.avatar"/>
 6      <h2>My Name is {{contentObject.name}}</h2>
 7      <h4>Biography</h4>
 8      <p>{{contentObject.bio}}</p>
 9    </div>
10
11    <!-- Render the placeholder template -->
12    <div v-else class="user-container placeholder">
13      <img class="avatar" src="/path/to/default-avatar.png"/>
14      <h2></h2>
15      <h4>Biography</h4>
16      <p></p>
17    </div>
18  </div>
19</template>
20
21...
22
23<style>
24.user-container.placeholder > *:not(img) {
25  background-color: rgba(0, 0, 0, 0.2);
26  filter: blur(7px);
27}
28
29.user-container.placeholder h2 {
30  height: 40px;
31  width: 50%;
32}
33
34.user-container.placeholder p {
35  height: 400px;
36  width: 30%;
37}
38</style>

扔一些过渡和清理它一点,你有一个相当可行的解决方案,你的网站! 只是,不是一个非常好的。

微笑数据

我的个人最喜欢的解决方案是将Classy Toggles方法与一些伪装数据相结合,然后实际数据加载,这样你仍然可以有一个非常容易维护的组件,而不必担心可能无效的数据。

我们将以这个方案为例:

1const person:Object = {
2  name: String,
3  avatar: String,
4  bio: String
5};
6
7const people: Array<person>;
 1<template>
 2  <div class="user-container">
 3    <img class="avatar" :src="https://cdn.jsdelivr.net/gh/andsky/tutorials-images/contentObject.avatar"/>
 4    <h2 :class="{placeholder: !contentObject.name}">My Name is {{contentObject.name}}</h2>
 5
 6    <h4>Biography</h4>
 7    <p :class="{placeholder: !contentObject.bio}">
 8      {{contentObject.bio}}
 9    </p>
10  </div>
11</template>
12
13<script>
14export default {
15  props: {
16    contentObject: {
17      type: Object,
18      default: {
19        avatar: '/path/to/default/avatar.png',
20        name: '',
21        bio: ''
22      }
23    }
24  }
25}
26</script>
27
28<style>
29.user-container * {
30  transition: all 200ms;
31  background-color: transparent;
32  color: inherit;
33  filter: none;
34}
35
36.user-container .placeholder {
37  color: transparent;
38  background-color: rgba(0, 0, 0, 0.2);
39  filter: blur(7px);
40}
41
42.user-container h2.placeholder {
43  height: 40px;
44  width: 50%;
45}
46
47.user-container p.placeholder {
48  height: 400px;
49  width: 30%;
50}
51
52</style>

这种方法具有具有相当简单的模板,仍然有CSS过渡的优势,并能够保持一个体面的数据模型(尽管需要更多的检查)。

避免无法读取未定义的 x 属性

几乎每个新的 Vue.js 开发人员都会遇到的一个经典错误是试图访问尚未初始化的对象上的属性,与 Angular 2+ 不同,Vue 没有?.prop?[prop] 存在运算器,所以没有一个简单、安全的方式来访问可能不存在的对象上的属性。

作为一个解决方案,你可以使用一个组件方法,重复检查水平,看看它是否有效。

然而,更好的解决方案是保持一个一致的模型. 在许多情况下,如果一个属性可能存在或可能不存在,这通常是代码气味的迹象。

Published At
Categories with 技术
Tagged with
comments powered by Disqus