Solve the Notification overlap problem of element-ui

While developing today, I encountered a problem:

Scenes:

There is an array. I need to traverse the array and render each item in the array in the lower right corner of the page using the Notification component of element-ui.

This is not simple, arr.forEach() can do it! ! !

tipsArr.forEach((item: string) => {
  this.$notify({
    title: item,
    message: '',
    position: 'bottom-right',
    type: 'warning',
    duration: 0,
    offset: 10
  });
})

But it doesn’t seem to go as smoothly as I thought, because after the code is written, the page display is like this, each piece of information is overlapped, and the effect is different from the official website display? ? ?

My reminder messages are all overlapped. Only after closing one message can I see the content of the next message. This is not the effect I want! ! ! I hope it can be tiled as shown on the official website.

Cause Analysis:

After that, by looking at the source code of notify, I found the reason:

let verticalOffset = options.offset || 0;
instances.filter(item => item.position === position).forEach(item => {
  verticalOffset += item.$el.offsetHeight + 16;
});
verticalOffset += 16;
instance.verticalOffset = verticalOffset;

Each Notification notification component needs to calculate the position where it should be displayed before it is displayed. It needs to know how many Notification notification instances are in front of it, and then further calculate the position where it should be displayed. Each time the spacing is calculated, the current element will be taken. Height: item.$el.offsetHeight, but because Vue’s asynchronous update queue has a buffering mechanism, the DOM is not updated when the first notification is rendered, resulting in a height of 0, and all the second notifications are just moved up. The default offset of 16px does not add the height of the first notification. Each subsequent notification only increases the spacing of 16px. The final rendered notification components overlap.

Solution:

Method 1: Use nextTick method

However, this method has certain limitations, that is, you know that there are only a few notification messages to be rendered, or you know the length of the array, and the length value of the array is not very long.

//已知 tipsArr的length值为2

this.$notify({
   title: tipsArr[0],
   message: '',
   position: 'bottom-right',
   type: 'warning',
   duration: 0,
   offset: 10
 });

 this.$nextTick(() => {
   this.$notify({
     title:  tipsArr[1],
     message: '',
     position: 'bottom-right',
     type: 'warning',
     duration: 0,
     offset: 10
   });
 })

Method 2: Use setTimeout

data() {
    return {
      timer: null
    }
},


tipsArr.forEach((item: string) => {
  this.timer = setTimeout(() => {
    this.$notify({
      title: item,
      message: '',
      position: 'bottom-right',
      type: 'warning',
      duration: 0,
      offset: 10
    });
  }, 0)
  this.$once('hook:beforeDestroy', () => {
    this.timer && clearTimeout(this.timer)
    this.timer = null
  })
})

Method 3: Use Promise

data() {
    return {
      notifyPromise: Promise.resolve()
    }
}


tipsArr.forEach((item: string) => {
  this.notifyPromise = this.notifyPromise.then(() => {
    this.$notify({
      title: item,
      message: '',
      position: 'bottom-right',
      type: 'warning',
      duration: 0,
      offset: 10
    });
  })
})

The result after the solution:

Guess you like

Origin blog.csdn.net/weixin_46422035/article/details/125430561