ElementUI

前言

24年的年度目标其中就有一个是进入开源社区,而万事开头难,一开始选了VueCore和ElementUI作为我的开始,也向VueCore交了一个PR,但是没发现这个issue上一周就被修复了,所以就没了下文。

但是ElementUI的issue挺有意思的,下面我们来细说下:

问题

issue长这样:牙齿尖尖的

这边也贴一个SFC的链接吧:SFC

刚看到这个issue还挺有意思的:这个bug是在菜单组件过多时,elementUI会将过长的menu进行收纳进一个展开栏中:

elementUI

也就是上图中的省略号那个区域

当我们hover或者click那个区域时,会弹出一个展开栏,里面包含了所有的菜单

但是这个issue的问题是,当我们点击展开栏,当菜单栏的长度过多,会导致展开栏的长度过长,页面会往下拓展,导致页面的滚动条出现,后面页面的视宽内容会被挤压。

挤压不要紧,这个应该是符合预期的,因为当菜单栏过多时,我们的展开栏的长度也会变长,他就需要有地方进行拓展。

但是问题是,这个组件有一个节流函数:

const getIndexPath = (index: string) => subMenus.value[index].indexPath

// Common computer monitor FPS is 60Hz, which means 60 redraws per second. Calculation formula: 1000ms/60 ≈ 16.67ms, In order to avoid certain chance of repeated triggering when `resize`, set wait to 16.67 * 2 = 33.34
const debounce = (fn: () => void, wait = 33.34) => {
   let timmer: ReturnType<typeof setTimeout> | null
  return () => {
    timmer && clearTimeout(timmer)
    timmer = setTimeout(() => {
      fn()
    }, wait)
  }
}

let isFirstTimeRender = true
const handleResize = () => {
  if (sliceIndex.value === calcSliceIndex()) return
   const callback = () => {
    sliceIndex.value = -1
    nextTick(() => {
       sliceIndex.value = calcSliceIndex()
     })
   }    // execute callback directly when first time resize to avoid shaking
   isFirstTimeRender ? callback() : debounce(callback)()
   isFirstTimeRender = false
 }

他是这样的:当我们页面的视宽发生变化时,会触发resize事件,然后会执行handleResize函数,这个函数会计算当前的菜单栏的长度,然后会执行一个节流函数,这个节流函数会在一定的时间内,只执行一次回调函数,这个回调函数就是计算当前的菜单栏的长度,然后将这个长度赋值给sliceIndex,然后页面就会根据这个长度来进行展开栏的展开。

搞笑的就来了:刚刚我们触发的滚动条,使得这个节流函数的触发,页面就开始抽搐了 ,因为这个节流函数的节流时间是33.34ms,而我们的滚动条的触发频率是16.67ms,所以这个节流函数就会被频繁的触发,导致页面的抽搐。

解决

那么怎么solve这个问题呢:

我一开始想到的是改这个scss的样式,但是这个样式是根据菜单栏的长度来进行展开的,所以改样式是不行的。

后面我发现这个节流函数的触发应该是来解决拖动视窗时组件的销毁和重建,那么我们有必要这么频繁的触发这个节流函数吗?我们是否可以将当他改变组件数量的时候再进行触发呢?

所以在原来的代码中加了一行:

if (sliceIndex.value === calcSliceIndex()) return

这个问题整体来说还算简单,但是我觉得这个问题还是挺有意思的,所以就记录下来了。

提了这个PR也让我复习了一下git的操作,以及体验到了开源项目的PR流程和规范,还是挺有意思的。

下一个阶段的小目标:向Vue和elementUI提PR,看能不能有机会进core team!