Vue.js 自定義組件封裝實錄——基於現有控件的二次封裝(以計時器為例)


在本人着手開發一個考試系統的過程中,出現了如下一個需求:制作一個倒計時的控件顯示在試卷頁面上。本文所記錄的就是這樣的一個過程。

前期工作

對於這個需求,自然我想到的是有沒有現成的組件可以直接使用(本着不重復發明輪子的原則)。於是我就在 GitHub 上找尋。確實找到了不少,但是與需求之間的差距還比較大。從零開始寫又不太現實(時間擺在那里,加之自己的前端也是剛學,還沒有從零開始手擼一個控件的能力),所以在已有組件的基礎上進行二次封裝便成了一個比較可行的方法(幾乎也是唯一解)。遂在 npm 上以 countdown 為關鍵詞搜索,最后找到了 Vue Awesome Countdown 這個組件。這個組件幾乎滿足了需求,只是它還沒有像樣的展示形式。所以針對它的二次封裝主要就是圍繞這個展開。

對於考試倒計時的組件,我希望它有兩個功能:在頁面上展示剩余時間、在考試結束時自動交卷。接下來的內容就圍繞這個展開。

時間顯示

要想在頁面上進行時間顯示。首先需要知道這個倒計時組件是如何保存時間的。翻閱文檔得知,保存在組件中的時間是以 timeObj 的形式進行存儲(timeObj 的完整格式見下)。對於需求來說,我們只需要其中的 timeObj.htimeObj.mtimeObj.s 即可。

{
    "endTime": 1542634411361,
    "speed": 1000,
    "leftTime": 97019,
    "d": "0",
    "h": "00",
    "m": "01",
    "s": "37",
    "ms": "019",
    "org": {
        "d": 0.001134247685185185,
        "h": 0.02722194444444444,
        "m": 1.6333166666666665,
        "s": 37.998999999999995,
        "ms": 19
    },
    "ceil": {
        "d": 1,
        "h": 1,
        "m": 2,
        "s": 98
    }
}

倒計時的時長,則可以通過后端傳過來的考試記錄信息進行推算,然后作為一個參數傳入,結合網站提供的示例,很快就寫出了以下代碼:

<template>
  <div id="timer-view">
    <p class="title">距離考試結束還有</p>
    <countdown :end-time="new Date().getTime() + remainingTimes">
      <div class="timer" slot="process" slot-scope="{ timeObj }">
        {{ `${timeObj.h}:${timeObj.m}:${timeObj.s}` }}
      </div>
    </countdown>
  </div>
</template>

<script>
export default {
  name: 'timer',
  props: {
    remainingTimes: Number
  }
}
</script>

<style scoped>
#timer-view {
  margin: 15px;
  border: solid 1px;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
}
.title {
  text-align: center;
}
.timer {
  text-align: center;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 50px;
  color: red;
  font-weight: bold;
}
</style>

計時結束事件

顯示的問題解決后,下面要處理的是計時結束后的自動交卷。官方文檔中提到了該組件有如下四個事件可以處理:

Event Explain Parameters
start Functions executed at the beginning of countdown vm
process Function executed when countdown is performed vm
stop Function executed when countdown stops vm
finish Function executed when countdown finished vm

不難看出,對於需求來說,可以響應它的 finish 事件完成這一功能。這里限於本人對 Vue 的事件響應了解還不是很透徹,這里采用了一個比較麻煩的手法處理該問題(將響應 finish事件的函數作為參數傳入組件,然后對應的部分直接寫 @finish="傳入的參數")。之后對 Vue 的理解更加深入后會改回事件響應的那套模型。

<!--
    計時器組件
    Author: 劉忠燏 (seLiuZhongyu@outlook.com)
  -->
<template>
  <div id="timer-view">
    <p class="title">距離考試結束還有</p>
    <countdown :end-time="new Date().getTime() + remainingTimes" @finish="endCallback">
      <div class="timer" slot="process" slot-scope="{ timeObj }">
        {{ `${timeObj.h}:${timeObj.m}:${timeObj.s}` }}
      </div>
    </countdown>
  </div>
</template>

<script>
export default {
  name: 'timer',
  props: {
    remainingTimes: Number,
    endCallback: Function
  }
}
</script>

<style scoped>
#timer-view {
  margin: 15px;
  border: solid 1px;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
}
.title {
  text-align: center;
}
.timer {
  text-align: center;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 50px;
  color: red;
  font-weight: bold;
}
</style>

以上就是計時器的完整代碼,要使用它,只要傳入合適的參數給該組件即可:

<template>
  <div>
    <timer :remaining-times="remainingTimes" :end-callback="onFinished"></timer>
  </div>
</template>

<script>
import Timer from '@/components/Timer'

export default {
  name: 'paper-view',
  components: {
    'timer': Timer
  },
  methods: {
    onFinished () {
      // ...
    },
  },
  computed: {
    remainingTimes () {
      // ...
    }
  }
}
</script>

<style>

</style>

總結

通過 這次的組件封裝,我對 Vue 的組件有了進一步的認識,也暴露出我在 Vue 的事件模型上了解得還不夠深入,在之后的工作中我還需要在這方面繼續深入學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM