如何向 Vuetify Snackbar 添加进度条?

How to add a progress bar to Vuetify Snackbar?

我寻找一种向 Vuetify 的 Snackbar 组件添加进度条的优雅方式。该栏必须与超时道具同步。我使用了 setInterval,但直接在组件上应用样式可能更好?

<template>
  <v-snackbar :value="true" :timeout="timeout" light>
    <span>Text to display</span>
    <v-progress-linear absolute bottom :value="progressValue" />
  </v-snackbar>
</template>

<script>
export default {
  name: 'SnackBarProgress',
  props: {
    timeout: {
      type: Number,
      default: 5000
    }
  },
  data: () => ({
    progressValue: 0,
    steps: 1,
    interval: null
  }),
  mounted() {
    this.startProgress();
  },
  beforeDestroy() {
    clearInterval(this.interval);
  },
  methods: {
    startProgress() {
      if (this.timeout < 1) {
        return;
      }

      clearInterval(this.interval);

      this.interval = setInterval(() => {
        if (this.steps === this.timeout) {
          clearInterval(this.interval);
          return;
        }

        this.steps = this.steps + 100;
        this.progressValue = Math.round((this.steps / this.timeout) * 100);
      }, 100);
    }
  }
};
</script>

我个人的做法是设置一个 setTimeout 来评估计时器的当前状态,并将其绑定到进度条。

首先,让我们创建一个接受与显示小吃店相关的 v-model 的组件。为此,我们需要一个 value 道具。我们还将为以毫秒为单位的超时创建一个属性,默认值为 5 秒。

props: {
    value: {
      default: false,
    },
    timeout: {
      default: 5 * 1000,
    },
}

接下来,我们将创建一个变量来跟踪我们当前的时间

data() {
  return {
    currentTime: 0,
  };
},

现在我们将创建我们的方法来使进度条每秒递增 10 次。如果当前时间大于超时时间,那么我们需要更新 v-model 来隐藏 snackbar

methods: {
 syncPbar() {
   //Create a timeout every 100 miliseconds
   setTimeout(() => {
     //Increment the time counter by 100
     this.currentTime += 100;

     //If our current time is larger than the timeout
     if (this.timeout <= this.currentTime) {

       //Wait 500 miliseconds for the dom to catch up, then reset the snackbar
       setTimeout(() => {            
         this.$emit("input", false); //Update the v-model to false
         this.currentTime = 0; // reset the current time
       }, 500);
     } else {
       //Recursivly update the progress bar
       this.syncPbar();
     }
   }, 100);
 }
}

然后我们需要监控值(来自 v-model),如果为真则开始倒计时。

watch: {
  value(v) {
    if (v) this.syncPbar();
  }
}

最后,我们将创建我们的模板。由于 v-progress-linear 期望值是 0-100,我们需要计算已经过去的时间百分比。最简单的方法是将 currentTimetimeout 相除,然后乘以 100。然而,这可能会给我们一个浮点数,因此我们需要使用 [=21 强制它为整数=] 所以我们四舍五入到最接近的百分点。我们还需要创建一个 slot 来承载我们小吃店的文本。

<template>
  <v-snackbar :value="value" light>
    <span>
      <slot></slot>
    </span>

    <v-progress-linear
      absolute
      bottom
      :value="Math.floor(100 * (currentTime / timeout))"
    />
  </v-snackbar>
</template>

现在我们已经创建了我们的组件,我们可以在我们的父级中使用它,我们只需要指定一个超时和一个 v-model。

<mySnack 
    v-model="showSnack"
    :timeout="5 * 1000"
    > 
      Snackbar text 
</mySnack>

要查看完整的工作示例,请查看我创建的 codesandbox