摘要

废弃 selectorxyoffset,改用 eltopleft(和 behavior),与原生 API 保持一致,并且更加灵活。

基本范例

  1. const router = new Router({
  2. scrollBehavior(to, from, savedPosition) {
  3. // scroll to id `can~contain-special>characters` + 200px
  4. return {
  5. el: '#can~contain-special>characters'
  6. // top relative offset
  7. top: 200
  8. // instead of `offset: { y: 200 }`
  9. }
  10. }
  11. })

scrollBehavior 返回的其他可能的值:

  1. // scroll smoothly (when supported by the browser) to 400px from top and 20px from left
  2. {
  3. top: 400,
  4. left: 20,
  5. behavior: 'smooth'
  6. }
  7. // scroll smoothly to selector .container
  8. {
  9. el: '.container'
  10. behavior: 'smooth'
  11. }
  12. // directly pass an Element to `el`
  13. {
  14. // use the fragment(to.hash) on the url but scroll to a child of it with a class `container`
  15. el: document.getElementById(to.hash.slice(1)).querySelector('.container')
  16. }

动机

废弃 selector

现有的滚动行为接受一个内部使用 document.querySelectorselector 属性。在 vue-router@3 中,我们目前对与 /^#\d/(以数字开头的 ID CSS 选择器)匹配的选择器有一个变通的方法。这是因为这样的选择器是无效的,所以我们检测到它并使用 document.getElementById 代替。然而,当使用像 #1one .container 这样的 CSS 复合选择器时,这就失效了。事实上,还有很多字符需要转义,我们不可能转义所有的字符,这就造成了滚动行为更难使用的情况。除此之外,当 vue-router 因为 document.querySelector 失败而抛出问题时,会让用户感到困惑。

废弃 xyoffset

目前有两种指定偏移量的方法,都使用了与原生函数不同的 x/y 坐标系统:原生浏览器函数允许在 scrollTo 方法中使用一个 [ScrollToOptions](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions)。这个对象包含 topleftbehavior 属性。

具体设计

尽管 RFC 中没有任何注视,**scrollBehavior** 仍然可以返回上述任何类型的 Promise。我们省略了对返回类型的关注,而不是让它在 scrollBehavior 中等待。

废弃 xy

这与 Element.scrollTo 一致,并使其更自然地传递额外的选项,如 behavior

  1. { x: 0, y: 200 }
  2. // becomes
  3. { left: 0, top: 200 }
  4. // it can accept `behavior`
  5. { left: 0, top: 200, behavior: 'smooth' }

废弃 offset

在指定偏移量时,我们可以直接接受 xyselector 一起,而不是在选择器旁边接受一个 offset 选项:

  1. {
  2. selector: '#getting-started',
  3. y: -120,
  4. }

在提案的重新命名后,将变为:

  1. {
  2. el: '#getting-started',
  3. top: -120,
  4. }

省略 el 将创建一个绝对偏移,就像我们在 vue-router@3 中提供 x 和/或 y 一样。

更加直观的选择器,感谢 el

一个新的 el 属性的目标是为大多数常见的使用情况提供简单的、“it just works” 的选择器,同时仍然允许高级情况:

  • to.hash 指的是页面上的一个 id,并且直接提供给 el。例如,当 to.hash 等于 #about#getting-started#symbols~work 时,el: to.hash
  • el 提供了一个更加通用的选择器,不一定来自 to.hash。例如,.container > main任何不以 **#** 开头的东西都可以。
  • el 提供了一个 Element,以允许任何高级的使用情况,例如,当 to.hash# 开头,但包含一个 CSS 选择器而不是一个 id:document.querySelector(to.hash)

由于允许原生 Element,这涵盖了所有可能的情况,并使之更容易在事情不成功时向用户提供反馈。

通过警告获得开发者体验

这一变化的另一个重要部分是在开发中,当 vue-router 找不到一个元素或 document.querySelector 抛出一个错误时,会发出警告。我们可以将其分为两种情况:

el# 开头

el# 开头时,我们内部使用 document.getElementById(el.slice(1))。如果它没有找到元素,在开发中模式下,我们尝试使用 document.querySelector(${providedEl}) 并解释原因。如果我们什么也没找到,就显示通常的警告:没有找到任何元素。

el 不以 # 开头

在开发者模式下,如果 document.querySelector throw,try catch 会提供一个错误信息,这个信息指向这篇伟大的文章 https://mathiasbynens.be/notes/css-escapes 并且指向 [CSS.escape](https://developer.mozilla.org/en-US/docs/Web/API/CSS/escape)。如果什么都没找到,就显示同样的警告,即没有找到任何元素。

缺点

  • 破坏性变化,但可以通过废弃来引入

备选方案

N/A

采纳策略

  • 在 v3 中删除 selectorxyoffset,并提出警告
  • 在 v4 中完全删除

没有解决的问题

N/A

注意

本 RFC 不涉及滚动到与窗口不同的元素或一次滚动多个元素的问题。