Day 25:「好慢喔,下载多少了?」- 进度条

Day25-Banner

终於到了我们的元件篇啦!!!

今天是第一个元件,所以稍微简单一点。
我们要来做下载的进度条~

carrotPoint 前置作业

我们这次要使用的专案环境是 Vue 的,所以之前建立过的那个专案就不沿用罗!

而 Tailwind + Vue 的专案要快速建立就得用到 Creator 啦!

Creator 连结在这边: 点我

进到 Creator 後,我这边专案名称是叫做 beautiful-components-libs,然後 template 选择 Vite 分类下的 Vue。

都 OK 之後,大力按下复制然後贴到你的 Terminal (cmd) 中,让他开始建立专案并开启 dev server。

开启後,我们浏览网站就会看到这个画面:

那这样前置作业就完成啦~
接着开启 vs code 准备开发!

(如果对这些步骤或是对 Creator 还不熟悉的人,建议你回去复习兔兔的 Day 18:「极速开发」- Vitawind)
 

carrotPoint 建立空白元件

首先,我们要先建立空白元件,
这样画面上就可以同步看到我们的修改内容。

先在专案里的 ./src/components 资料夹中新增一个 ProgressBar.vue 的元件:

完成後,增添以下内容:

<template>
  
</template>

<script>
export default {
  name: "ProgressBar",
}
</script>

<style>

</style>

接着我们就可以把这个元件新增到画面中,打开 App.vue 然後改成以下内容:

<template>
  <div :class="[
    'w-screen h-screen',
    'flex flex-col',
    'justify-center items-center',
    'gap-5',
  ]">
    <ProgressBar />
  </div>
</template>

<script>
import ProgressBar from './components/ProgressBar.vue'

export default {
  components: {
    ProgressBar
  }
}
</script>

这时候画面上 ... 是空白的!

对,因为我们把 HelloWorld.vue 从画面上去掉了,加入了我们建立的 ProgressBar 元件,然後因为元件内容都还没有做,所以画面是空白的。

再来,就要来开始做我们的进度条罗!
 

carrotPoint 进度条

我们先来看一下,进度条可能会有的样子!

所以很明显,这就是要分成三层,
既然知道了,就 div 大法直接建 3 层

像这样:

<template>
  <div>
    <div>
      <div />
    </div>
  </div>
</template>

<script>
export default {
  name: "ProgressBar",
}
</script>

建好之後,都先填上背景颜色:

<div :class="[
  'bg-gray-200'
]">
  <div :class="[
    'bg-green-800'
  ]">
    <div :class="[
      'bg-green-500'
    ]" />
  </div>
</div>

因为现在都还没有宽度高度,所以画面上还是没有东西。 我们帮最外层设定高度 w-80 并增加一点内距 p-5

<div :class="[
  'w-80 p-5',
  'bg-gray-200'
]">
  <div :class="[
    'bg-green-800'
  ]">
    <div :class="[
      'bg-green-500'
    ]" />
  </div>
</div>

看起来有点 ... 样子?

还没,我们再来帮进度条背景和进度条本体设定宽度高度,进度条背景的宽高设为 w-full h-2,然後进度条本体的宽高设定为 w-1/3 h-full

<div :class="[
  'w-80 p-5',
  'bg-gray-200'
]">
  <div :class="[
    'w-full h-2',
    'bg-green-800'
  ]">
    <div :class="[
      'w-1/3 h-full',
      'bg-green-500'
    ]" />
  </div>
</div>

这次是不是真的有点 fu 了?
对啦~一定有啦~我知道啦~

可是根据小米定律,要好看的话肯定要加上什麽?

大声点,我听不到! 梁静茹也听不到!

嘿啦~就是圆角啦!

我们帮最外层加上大量级的圆角 rounded-lg,然後帮进度条背景和进度条本体都加上 rounded-full

<div :class="[
  'w-80 p-5',
  'bg-gray-200',
  'rounded-lg'
]">
  <div :class="[
    'w-full h-2',
    'bg-green-800',
    'rounded-full'
  ]">
    <div :class="[
      'w-1/3 h-full',
      'bg-green-500',
      'rounded-full'
    ]" />
  </div>
</div>

嗯~~~很可以。

是不是! 我就说小米定律超有效的啦!
质感整个大提升了。

但现在只是固定的画面,所以我们要让它可以实际使用!
要让它动起来了!
 

carrotPoint 动起来

接下来就是要写 Vue 的部分了。

这时候可以仔细的思考一下,
进度条会需要什麽东西?

答案就是:最小值最大值现在值

所以我们就帮元件加上 props,分别是 minValmaxValcurrentVal

<script>
export default {
  name: "ProgressBar",
  props: ["minVal","maxVal","currentVal"],
}
</script>

加好之後,我们需要算进度是多少 % 。

在 data 中建立一个变数 percent 来储存算完的结果,预设值是 0。

但是光是建立好变数,还没建立算式呢! 这时候我们要使用之前没说过的东西:watch 来完成。

之前在 Day 20 有谈过类似的概念,而 Vue 中的 watch 呢就是可以用来监看某个变数或物件是否有变动,然後触发你所指定的方法。

因为我们这里需要在 currentVal 变动时重新计算进度是多少 % ,所以我们写在 watch 之中:

<script>
export default {
  name: "ProgressBar",
  props: ["minVal","maxVal","currentVal"],
  data() {
    return {
      percent: 0,
    }
  },
  watch: {
    currentVal(newVal, oldVal) {
      this.percent = newVal <= this.minVal ? 0 : (newVal-this.minVal)*100/(this.maxVal-this.minVal)
    }
  }
}
</script>

最後,因为元件建立时载入初始值的当下不算是变数内容的变动,所以我们要在元件挂载时重新计算一次:

<script>
export default {
  name: "ProgressBar",
  props: ["minVal","maxVal","currentVal"],
  data() {
    return {
      percent: 0,
    }
  },
  mounted() {
    this.percent = this.currentVal <= this.minVal ? 0 : (this.currentVal-this.minVal)*100/(this.maxVal-this.minVal)
  },
  watch: {
    currentVal(newVal, oldVal) {
      this.percent = newVal <= this.minVal ? 0 : (newVal-this.minVal)*100/(this.maxVal-this.minVal)
    }
  }
}
</script>

那麽我们就 ... 啊!

修但几咧,差点就忘了最重要最重要的点
我们的 % 算完还没让它应用到高度上啊 XD

所以,我们贴心的帮进度条本体绑定 style,用 percent 来动态改变宽度:

<div :class="[
  'w-80 p-5',
  'bg-gray-200',
  'rounded-lg'
]">
  <div :class="[
    'w-full h-2',
    'bg-green-800',
    'rounded-full'
  ]">
    <div 
      :class="[
        'w-1/3 h-full',
        'bg-green-500',
        'rounded-full'
      ]"
      :style="{
        width: percent + '%'
      }"
    />
  </div>
</div>

这样就真的完成了!

最後元件的完整内容会是这样:

<template>
  <div :class="[
    'w-80 p-5',
    'bg-gray-200',
    'rounded-lg'
  ]">
    <div :class="[
      'w-full h-2',
      'bg-green-800',
      'rounded-full'
    ]">
      <div 
        :class="[
          'w-1/3 h-full',
          'bg-green-500',
          'rounded-full'
        ]"
        :style="{
          width: percent + '%'
        }"
      />
    </div>
  </div>
</template>

<script>
export default {
  name: "ProgressBar",
  props: ["minVal","maxVal","currentVal"],
  data() {
    return {
      percent: 0,
    }
  },
  mounted() {
    this.percent = this.currentVal <= this.minVal ? 0 : (this.currentVal-this.minVal)*100/(this.maxVal-this.minVal)
  },
  watch: {
    currentVal(newVal, oldVal) {
      this.percent = newVal <= this.minVal ? 0 : (newVal-this.minVal)*100/(this.maxVal-this.minVal)
    }
  }
}
</script>

元件完成之後,我们就可以来测试啦!
 

carrotPoint 测试

再测试之前,我们要先来完善一下我们的测试环境

回到 App.vue,我们来增加一个拉杆的 input 元素,不然一直改来改去很累,不如用拉的来改变数值!

<div :class="[
  'w-screen h-screen',
  'flex flex-col',
  'justify-center items-center',
  'gap-5',
]">
  <input type="range" />
  <ProgressBar />
</div>

加好之後,我们也需要从外部帮他们两个元件设定最小值、最大值,然後让进度条元件的 currentVal 与拉杆的当前值同步,最後就会是这个样子:

<template>
  <div :class="[
      'w-screen h-screen',
      'flex flex-col',
      'justify-center items-center',
      'gap-5',
  ]">
    <input type="range" v-model="val" :min="min" :max="max" />
    <ProgressBar :currentVal="val" :minVal="min" :maxVal="max" />
  </div>
</template>

<script>
import ProgressBar from './components/ProgressBar.vue'

export default {
  data() {
    return {
      min: 0,
      max: 200,
      val: 100,
    }
  },
  components: {
    ProgressBar,
  }
}
</script>

那麽可以测试了!
我们回到画面上玩玩~

耶~大成功!
 

carrotPoint 进阶修改

虽然像是做完了,不过还有一些可以再加强的地方!

毕竟这样还是不够灵活、不够华丽呀~

所以最简单的,我们先加上个过渡效果,且 duration 设为 0.5 s:

<div :class="[
  'w-80 p-5',
  'bg-gray-200',
  'rounded-lg'
]">
  <div :class="[
    'w-full h-2',
    'bg-green-800',
    'rounded-full'
  ]">
    <div 
      :class="[
        'w-1/3 h-full',
        'bg-green-500',
        'rounded-full',
        'transition-all duration-500'
      ]"
      :style="{
        width: percent + '%'
      }"
    />
  </div>
</div>

加完之後,应该觉得顺畅多了吧?

「是没错啦,华丽的部份解决了 ... 但兔兔你说的灵活度呢?」

灵活度吗,好!
这就要靠 slot 啦~

我们可以运用 slot 的 props,把资料从内部拉出来外部使用,像是:

<div :class="[
  'w-80 p-5',
  'bg-gray-200',
  'rounded-lg',
  'flex flex-col',
  'justify-center items-center',
  'gap-3'
]">
  <slot
    :minVal="minVal"
    :maxVal="maxVal"
    :currentVal="currentVal"
    :percent="percent"
  />
  <div :class="[
    'w-full h-2',
    'bg-green-800',
    'rounded-full'
  ]">
    <div 
      :class="[
        'w-1/3 h-full',
        'bg-green-500',
        'rounded-full',
        'transition-all duration-500'
      ]"
      :style="{
        width: percent + '%'
      }"
    />
  </div>
</div>

然後为了让文字和进度条可以直向排列,我还另外在外框多下了 flex flex-col 的样式,然後记得给一点空隙,才不会看起来太挤。

 
这样做之後,我们就可以弄出像这样子的效果:

<ProgressBar
  :currentVal="val" :minVal="min" :maxVal="max"
  v-slot="{ percent }"
>
  已下载 {{ percent }} %
</ProgressBar>

不仅如此,
也可以轻松修改出像是游戏载入资源的进度条:

<ProgressBar
  :currentVal="val" :minVal="min" :maxVal="max"
  v-slot="{ maxVal, currentVal }"
>
  正在准备资源 ({{currentVal}} / {{maxVal}}) 
</ProgressBar>

那就会看起来像是这样~

这麽一来就完全做完啦!
 

好的,那麽今天的进度条就是这麽轻松简单~

明天的也很简单喔,
我们要来完成各种按钮的变化!

是不是跃跃欲试啦?
那我就不说这麽多了,赶快留时间给你去做做看!
 

carrotPoint 给你们的回家作业:


关於兔兔们:


 


( # 兔兔小声说 )

今天兔兔喉咙烧声,说不出话。
但是可以唱歌!

(欸你这明明就是选择性的!)


<<:  Day11 Buddy, slab 记忆体管理大将

>>:  买大买小!下好离手 - 下单

Day 18: LeetCode 322. Coin Change

Day 18: LeetCode 322. Coin Change Tag: follow John...

Day-10 全部都交给它就好的懒人怀旧神器 RetroTINK

写文至今已介绍过 XRGB-mini 跟 OSSC 这两种神器、互有上下也都能得到相当好的效果。但身...

鬼故事 - 我们有通过国际资安 OOO 标准

鬼故事 - 我们有通过国际资安 OOO 标准 credit: AilinStock, DNDmeme...

DAY9-EXCEL统计分析:常用的统计量

叙述统计表 今天一家电脑公司为了了解该电脑在一地区销售的远景,所以利用近60天的销售报表,试求该电脑...

[Day26] QA 与系统

「老板,为因应多国语系,以及多平台的支援,我要增加 QA 团队的编制到对应的国家数与平台数。」这是我...