geeeger / blog

https://loofp.com
1 stars 0 forks source link

html 锚点定位及tabs栏tab定位激活的实现 #12

Open geeeger opened 4 years ago

geeeger commented 4 years ago
  1. 实现导航元素粘性定位。

鉴于chrome内核 56开始支持sticky定位,那么首先要解决tabs栏定位问题,此方案可以有兼容方案 sticky定位caniuse 1 检测sticky定位支持,如果支持,则导航栏直接使用sticky定位,检测方式摘自stickybits.js

checkIfStickySupport() {
  let test = document.head.style
  let perfix = ['', '-webkit-']

  for (let index = 0; index < perfix.length; index++) {
    const element = perfix[index];
    test.position = `${element}sticky`
  }

  let support = Boolean(test.position)

  test.position = ''

  return support
}

2 针对不支持sticky定位的环境,fallback至fixed定位

if (!supportSticky) {
  if (scrollTop > anchorOffsetTop) {
    anchor.style.position = 'fixed'
  } else {
    anchor.style.position = ''
  }
}
  1. 针对滚动到某一项,则tabs对应激活相应锚点的tab,此处使用比较锚点元素的offsetTop和滚动容器的滚动高度来实现
    
    let scrollTop = document.body.scrollTop || document.documentElement.scrollTop
    let tops = domList.map(item => item.offsetTop - offset)
    let pos = 0

if (scrollTop <= tops[0]) { // do nothing } else { for (let index = 0; index < tops.length; index++) { const top = tops[index]; if (scrollTop > top) { pos = index } } }

if (tops.length === 3 && pos !== 0) { pos = pos + 1 }

this.activeIndex = pos

4. 针对点击tab跳转到对应锚点,可有以下方案
4.1 针对支持scrollIntoView并支持平滑滚动的元素,直接使用平滑滚动方案,滚动至锚点位置(此方案不支持自定义offset位移)
```javascript
if (isSupportScrollIntoViewOptions) {
  element.scrollIntoView({
    behavior: 'smooth',
    block: 'start',
    inline: 'start'
  })
}

4.2 针对不支持的,但支持RAF的,fallback至RAF滚动

else if (isSupportRequestAnimationFrameApi) {
  const offsetTop = element.offsetTop
  const scrollableParent = getScrollParent(element)
  const scrollTop = scrollableParent.scrollTop
  const delta = offsetTop - scrollTop - offset
  const perStep = delta / stepNum
  let times = 0
  let step = () => {
    if (times >= stepNum) {
      return
    }
    scrollableParent.scrollTop += (perStep - 1)
    times++
    window.requestAnimationFrame(step)
  }
  window.requestAnimationFrame(step)
}

4.3 针对以上都不支持的,fallback至一般scrollIntoView方法(不支持options参数)

else {
  element.scrollIntoView(true)
}