【问题标题】:VUE 3 - using setInterval to remove items from arrayVUE 3 - 使用 setInterval 从数组中删除项目
【发布时间】:2020-12-30 01:22:56
【问题描述】:

我想使用 VUE 3 创建一个简单的 Snackbar。我已经在 Vue 2 中完成了这项工作,但 Vue3 的工作方式似乎略有不同。

我已将消息数组保存在商店中,如下所示:

import { createStore } from 'vuex'

export default createStore({
  state: {
    snackbarText: []
  },
  mutations: {
    DELETE_SNACKBAR_MESSAGE(state) {
      state.snackbarBarText.shift()
    },
    ADD_SNACKBAR_MESSAGE(state, message) {
      state.snackbarBarText.push(message)
    }
  },
  getters: {
    MESSAGES: (state) => state.snackbarText
  }
})

这就是我目前在 Snackbar.vue 组件中的内容:

import { useStore } from 'vuex';
import { ref, watch} from 'vue';

export default {
  set() {
    const store = useStore();
    const text = ref(store.getters["MESSAGES"]);
    
    if (text.value.length) {
      let timer = setInterval(() => {
        store.commit('DELETE_SNACKBAR_MESSAGE');
        
        if (text.value.length) {
          clearInterval(timer)
        }
      }, 3000)
    }    

    return { text }
  }
}

有没有办法检查 Snackbar 中 text 引用的长度并调用启动计时器的函数?我只是很难在 Vue3 中实现这一点,因为我还不太熟悉 Composition API。

它应该工作的方式是将消息添加到数组中并显示给用户。 3 秒后,它们从阵列中移除。使用 watch 很笨拙,并且在 setInterval 停止后我很难重新启动它。

谢谢!

【问题讨论】:

    标签: javascript vue.js vuejs3


    【解决方案1】:

    !重写我使用setInterval 的原始答案。 setInterval 不适用于这种特定类型的功能。您不能以“干净”的方式从一个元素过渡到下一个元素。

    在 Vue2 中,您可能会使用 EventBus 来监听小吃栏消息数组的任何更改。但是在 Vue3 中,他们删除了该功能。您可以继续使用类似 EventBus 的模块或使用 subscribe

    这是整个组件:

    <template>
      <transition name="component-fade" @after-leave="checkForMoreSnacks">
        <div class="snackbar" v-if="currentSnack">
          <div class="snackbar__container">
            <p>{{ currentSnack }}</p>
            <button @click="closeCurrentSnack">Close Me</button>
          </div>
        </div>
      </transition>
    </template>
    
    <script>
    import { useStore } from "vuex";
    import { computed, ref } from "vue";
    export default {
      setup() {
        const timerInterval = 1500;
        const store = useStore();
        let timeoutToken = null;
        let snacks = computed(() => store.getters["GET_SNACKBAR_MESSAGES"]);
        let currentSnack = ref(null);
    
        // The event that triggers the Snackbar to initially appear.
        // Much like an EventBus emit
        store.subscribe(mutation => {
          // listen for this specific mutation call
          if (mutation.type === "ADD_SNACKBAR_MESSAGE") {
            // if there is already a currentSnack don't proceed
            if (currentSnack.value) return;
    
            // if no token, set the value to this settimeout function where we do:
            // 1. Set the current value to the [0] index of the snacks array.
            // 2. Remove that item from the snacks array in the store
            currentSnack.value = snacks.value[0];
            timeoutToken = setTimeout(() => {
              closeCurrentSnack();
            }, timerInterval);
          }
        });
    
        function closeCurrentSnack() {
          store.commit("DELETE_SNACKBAR_MESSAGE");
          currentSnack.value = null;
          timeoutToken = null;
        }
    
        function checkForMoreSnacks() {
          if (!snacks.value.length) {
            timeoutToken = null;
            currentSnack.value = null;
          } else {
            currentSnack.value = snacks.value[0];
            timeoutToken = setTimeout(() => {
              closeCurrentSnack();
            }, timerInterval);
          }
        }
    
        return {
          currentSnack,
          checkForMoreSnacks,
          closeCurrentSnack
        };
      }
    };
    </script>
    
    <style lang="scss" scoped>
    .snackbar {
      position: absolute;
      right: 10px;
      bottom: 10px;
      max-width: 500px;
      border: solid 2px red;
      padding: 1rem;
      border-radius: 5px;
    
      &__container {
        display: grid;
        grid-template-columns: 1fr;
        grid-template-rows: 1fr 30px;
      }
    }
    
    .component-fade-enter-active,
    .component-fade-leave-active {
      transition: opacity 0.3s ease;
    }
    
    .component-fade-enter-from,
    .component-fade-leave-to {
      opacity: 0;
    }
    </style>
    

    关键在于@after-leave 钩子。我意识到一旦显示的snackbar被移除,我们可以使用那个钩子检查更多。

    那个钩子也是不使用setInterval的原因。

    还为此创建了一个 git repo

    【讨论】:

      猜你喜欢
      • 2017-08-08
      • 2018-07-20
      • 1970-01-01
      • 2021-10-19
      • 2022-01-13
      • 2021-10-03
      • 2014-09-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多