[重构倒数第12天] - Vue3 directive 与 Skeleton 实战组合应用

前言

该系列是为了让看过Vue官方文件或学过Vue但是却不知道怎麽下手去重构现在有的网站而去规画的系列文章,在这边整理了许多我自己使用Vue重构很多网站的经验分享给读者们。

在前面的章节,我们讲了许多 vue3 directive 的使用方式还有实际应用,接下来我们要把我们前面所讲的 Skeleton 还有我们的 directive 给结合在一起,做一个组合的实战应用。

You should use Skeleton : https://ithelp.ithome.com.tw/articles/10260925

这就是我们要处理,透过 directive + skeleton 完成以下的实际案例。

mike vue

首先我先把资料给拿到手,我透过 axios来拿资料

<script>
import { ref, onMounted } from "vue";
import axios from "axios";
export default {
  setup() {
    const postCard = ref([]);
    const isLoad = ref(true);

    onMounted(() => {
      axios
        .get("https://60bd9841ace4d50017aab3ec.mockapi.io/api/post_card")
        .then((res) => {
          postCard.value = res.data;
          isLoad.value = false;
        });
    });

    return {
      postCard,
      isLoad,
    };
  },
};
</script>

这边会看到我宣告了两笔资料,postCard是我拿来存放 API 回来的资料,isLoad是让我判断 API 的资料回来没有,接下来我们来看一下我们的 html 的部分

<template>
  <div class="card" v-for="card in postCard" :key="card.id">
    <header>
      <img v-src="card.avatar" class="avatar load" />
      <div>
        <h1 :class="{ load: isLoad }">{{ isLoad ? "" : card.name }}</h1>
        <p :class="{ load: isLoad }" v-timeformat="card.post_date"></p>
      </div>
    </header>
    <p :class="['content', { load: isLoad }]">
      {{ isLoad ? "" : card.content }}
    </p>
    <img class="post_photo load" v-src="card.photo" alt="" />
  </div>
</template>

首先你会看到图片的地方我使用了 v-src的这个模板语法,这就是我们在上一个章节所提到的用 directive包起来的方法。

app.directive("src", (el, binding) => {
  if (binding.value) {
    const img = new Image();
    img.src = binding.value;
    img.onload = () => {
      el.src = binding.value;
    };
  }
});

然後所有跟文字有关的地方都加上了一个 load 的class,这个 load 的class 就是为了让我们可以在资料回来以前,让我们的文字区块出现灰色色块所准备的,然後再里面的内文我用了 isLoad来判断要不要让文字显示出来。

h1.load, p.load {
  display: block;
  width: 300px;
  height: 14px;
  background-color: #ededed;
  color: rgba(#fff, 0);
}

@keyframes loading {
  to {
    background-position-x: -20%;
  }
}

.load {
    background: linear-gradient(
        100deg,
        rgba(256, 256, 256, 0) 30%,
        rgba(256, 256, 256, 0.5) 50%,
        rgba(256, 256, 256, 0) 30%
    )
        #ededed;
    background-size: 200% 100%;
    background-position-x: 180%;
    animation: 2s loading ease-in-out infinite;
}

透过这样的方式我就可以很简单的处理图片的 load以及 Skeleton所需要显示的那些区块

import dayjs from "dayjs";

// 其他省略...

app.directive("timeformat", {
  mounted(el, binding) {
    const time = dayjs(binding.value).format("YYYY年MM月DD日");
    el.innerText = time;
  },
});

最後时间的部分处理就用了 v-timeformat这个方法就大功告成了。

Vue mike

以下就是完整的程序码的部分

// index.js

import { createApp } from "vue";
import App from "./App.vue";
import dayjs from "dayjs";

const app = createApp(App);

app.directive("src", (el, binding) => {
  if (binding.value) {
    const img = new Image();
    img.src = binding.value;
    img.onload = () => {
      el.src = binding.value;
    };
  }
});

app.directive("timeformat", {
  mounted(el, binding) {
    const time = dayjs(binding.value).format("YYYY年MM月DD日");
    el.innerText = time;
  },
});

app.mount("#app");

// App.vue

<script>
import { ref, onMounted } from "vue";
import axios from "axios";
export default {
  setup() {
    const postCard = ref([]);
    const isLoad = ref(true);

    onMounted(() => {
      axios
        .get("https://60bd9841ace4d50017aab3ec.mockapi.io/api/post_card")
        .then((res) => {
          postCard.value = res.data;
          isLoad.value = false;
        });
    });

    return {
      postCard,
      isLoad,
    };
  },
};
</script>

<template>
  <div class="card" v-for="card in postCard" :key="card.id">
    <header>
      <img v-src="card.avatar" class="avatar load" />
      <div>
        <h1 :class="{ load: isLoad }">{{ isLoad ? "" : card.name }}</h1>
        <p :class="{ load: isLoad }" v-timeformat="card.post_date"></p>
      </div>
    </header>
    <p :class="['content', { load: isLoad }]">
      {{ isLoad ? "" : card.content }}
    </p>
    <img class="post_photo load" v-src="card.photo" alt="" />
  </div>
</template>

<style lang="scss">
.card {
  width: 400px;
  height: auto;
  background-color: #fff;
  box-shadow: 0 0 5px rgba(#000, 0.3);
  margin: 0 auto 30px auto;
  header {
    display: flex;
    padding: 10px 10px 0px 10px;
    margin: 0 0 5px 0;
    color: #666;
    h1 {
      font-size: 15px;
    }
    p {
      font-size: 13px;
    }
  }
  p.content {
    font-size: 14px;
    padding: 0px 10px 10px 10px;
    color: #666;
    &.load {
      display: block;
      width: 200px;
      height: 14px;
      background-color: #ededed;
      color: rgba(#fff, 0);
      margin: 10px 10px 10px 10px;
    }
  }
}
img.avatar {
  width: 40px;
  height: 40px;
  border-radius: 50px;
  margin-right: 10px;
  background-color: #ededed;
}
img.post_photo {
  width: 100%;
  height: 300px;
  background-color: #ededed;
}
h1.load {
  display: block;
  width: 300px;
  height: 14px;
  background-color: #ededed;
  margin-bottom: 10px;
  color: rgba(#fff, 0);
}
p.load {
  display: block;
  width: 100px;
  height: 14px;
  background-color: #ededed;
  color: rgba(#fff, 0);
}
@keyframes loading {
  to {
    background-position-x: -20%;
  }
}

.load {
  background: linear-gradient(
      100deg,
      rgba(256, 256, 256, 0) 30%,
      rgba(256, 256, 256, 0.5) 50%,
      rgba(256, 256, 256, 0) 30%
    )
    #ededed;
  background-size: 200% 100%;
  background-position-x: 180%;
  animation: 2s loading ease-in-out infinite;
}
</style>

先告一个段落

我们今天特别把之前所讲过的东西给组合在一起 (Skeletondirective),就是让大家知道其实我们在实际的开发上面,技术处理都是复合式的应用,不会只使用单一的概念来进行开发,所以特别把这两个组合应用分享给大家知道,也是希望大家在实际开发的时候可以更加的融会贯通,那今天就先到这边告一个段落了,我们明天见罗!

QRcode

那如果对於Vue3不够熟的话呢?

Ps. 购买的时候请登入或注册该平台的会员,然後再使用下面连结进入网站点击「立即购课」,这样才可以让我获得更多的课程分润,还可以帮助我完成更多丰富的内容给各位。

我有开设了一堂专门针对Vue3从零开始教学的课程,如果你觉得不错的话,可以购买我课程来学习
https://hiskio.com/bundles/9WwPNYRpz?s=tc

那如果对於JS基础不熟的朋友,我也有开设JS的入门课程,可以参考这个课程
https://hiskio.com/bundles/b9Rovqy7z?s=tc

订阅Mike的频道享受精彩的教学与分享

Mike 的 Youtube 频道
Mike的medium
MIke 的官方 line 帐号,好友搜寻 @mike_cheng


<<:  [Day04] TS:如何把物件型别的所有属性名称取出变成 union type?试试看 keyof 吧!

>>:  State 和生命周期(上)(Day5)

损失函数的演进--2

triplet loss 接下来的Loss function为triplet loss 是为2015...

[Day 06] 监控、维护 — 自己开一家徵信社吧!

大家好,在开始之前先祝大家中秋节快乐~~ 监控 (Monitor) 最常见的监控方法为仪表板 (Da...

CLOUDWAYS 服务器方案评比 - linode / VULTR-HF / Digital Ocean-DP

在 CLOUDWAYS❐ 中,提供了5大云端主机供应商的方案☞ linode 、 VULTR 、 D...

Day16:卡文一篇,难解

WebRTC 在实作上遇到蛮多难题的,想要转成文章,理解程度仍然不足,只能花更多时间来研究了,不确定...

Day 3 - 基本资料型态、输入、基本运算式

大家好,我是长风青云。今天是铁人赛第三天,也是中秋连假第一天。 youtube影片在上字幕的部分,後...