在短时间内多次呼叫时,父级未收到vue.js $

时间:2017-12-07 15:17:17

标签: vue.js vuejs2 settimeout

我尝试实施一个简单的通知系统,其中包含受此片段形式Linus Borg启发的通知商店:https://jsfiddle.net/Linusborg/wnb6tdg8/

当您一次添加一个通知时它工作正常,但是当您在第一个通知消失之前添加第二个通知时,notificationMessage会发出" close-notification"事件但父通知组件组件不执行" removeNotification"功能。如果您在通知上使用click事件,则会在emit之后调用removeNotification。因此,超时可能存在问题,但我无法弄清楚是什么。

NotificationStore.js

class NotificationStore {
  constructor () {
    this.state = {
      notifications: []
    }
  }
  addNotification (notification) {    
    this.state.notifications.push(notification)
  }
  removeNotification (notification) {
    console.log('remove from store')
    this.state.notifications.splice(this.state.notifications.indexOf(notification), 1)
  }
}

export default new NotificationStore()

App.vue

<template>
  <div id="app">
    <notification-box></notification-box>
    <div @click="createNotif">
      create new notification
    </div>
  </div>
</template>

<script>
  import notificationMessage from './components/notificationMessage.vue'
  import notificationBox from './components/notificationBox.vue'
  import NotificationStore from './notificationStore'

  export default {
    name: 'app',
    methods: {
      createNotif () {
        NotificationStore.addNotification({
          name: 'test',
          message: 'this is a test notification',
          type: 'warning'
        })
      }
    },
    components: {
      notificationMessage,
      notificationBox
    }
  }
</script>

notificationBox.vue

<template>
  <div :class="'notification-box'">
      <notification-message v-for="(notification, index) in notifications" :notification="notification" :key="index" v-on:closeNotification="removeNotification"></notification-message>
  </div>
</template>

<script>
  import notificationMessage from './notificationMessage.vue'
  import NotificationStore from '../notificationStore'

  export default {
    name: 'notificationBox',
    data () {
      return {
        notifications: NotificationStore.state.notifications    
      }
    },
    methods: {
      removeNotification: function (notification) {
        console.log('removeNotification')
        NotificationStore.removeNotification(notification)
      }
    },
    components: {
      notificationMessage
    }
  }
</script>

notificationMessage.vue

<template>
    <div :class="'notification-message ' + notification.type" @click="triggerClose(notification)">
      {{ notification.message }}
    </div>
</template>

<script>
  export default {
    name: 'notificationMessage',
    props: {
      notification: {
        type: Object,
        required: true
      },
      delay: {
        type: Number,
        required: false,
        default () {
          return 3000
        }
      }
    },
    data () {
      return {
        notificationTimer: null
      }
    },    
    methods: {
      triggerClose (notification) {
        console.log('triggerClose')
        clearTimeout(this.notificationTimer)
        this.$emit('closeNotification', notification)
      }
    },
    mounted () {
      this.notificationTimer = setTimeout(() => {
        console.log('call trigger close ' + this.notification.name)
        this.triggerClose(this.notification)
      }, this.delay)
    }
  }
</script>

感谢您的帮助

1 个答案:

答案 0 :(得分:2)

我在后面的那个小小提琴仍在进行我看到的回合:D

这个小提琴仍在使用Vue 1.在Vue 2中,你必须键入你的列表元素,你试图这样做。

但是key应该是一个可靠地标识数据项的唯一值。您正在使用不执行此操作的数组索引 - 只要删除元素,就会更改以下项的索引。

这就是为什么你看到你所看到的行为:Vue无法可靠地删除正确的元素,因为我们的密钥不起作用。

所以我建议使用像nanoid之类的包来为每个通知创建一个真正唯一的ID - 但是一个简单的计数器可能也会起作用:

let _id = 0
class NotificationStore {
  constructor () {
    this.state = {
      notifications: []
    }
  }
  addNotification (notification) {    
    this.state.notifications.push({ ...notification, id: _id++ })
  }
  removeNotification (notification) {
    console.log('remove from store')
    this.state.notifications.splice(this.state.notifications.indexOf(notification), 1)
  }
}

并在通知组件中:

<notification-message 
  v-for="(notification, index) in notifications" 
  :notification="notification" 
  :key="notification.id"
  v-on:closeNotification="removeNotification"
></notification-message>