Skip to content

Commit f2ab0ec

Browse files
committed
initial version
1 parent 25d45eb commit f2ab0ec

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed

Diff for: active-rfcs/0000-router-scroll-position.md

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
- Start Date: 2020-05-31
2+
- Target Major Version: Vue Router v3 and v4
3+
- Reference Issues: https://github.com/vuejs/vue-router/issues/3008,
4+
- Implementation PR: (leave this empty)
5+
6+
# Summary
7+
8+
Deprecate `selector`, `x`, `y` and `offset` and introduce instead `el`, `top`, `left` (and `behavior`) that align with native apis and are more flexible.
9+
10+
# Basic example
11+
12+
```js
13+
const router = new Router({
14+
scrollBehavior(to, from, savedPosition) {
15+
16+
// scroll to id `can~contain-special>characters` + 200px
17+
return {
18+
el: '#can~contain-special>characters'
19+
// top relative offset
20+
top: 200
21+
// instead of `offset: { y: 200 }`
22+
}
23+
}
24+
})
25+
```
26+
27+
Other possible values returned by `scrollBehavior`:
28+
29+
```js
30+
// scroll smoothly (when supported by the browser) to 400px from top and 20px from left
31+
{
32+
top: 400,
33+
left: 20,
34+
behavior: 'smooth'
35+
}
36+
37+
// scroll smoothly to selector .container
38+
{
39+
el: '.container'
40+
behavior: 'smooth'
41+
}
42+
43+
// directly pass an Element to `el`
44+
{
45+
// use the fragment(to.hash) on the url but scroll to a child of it with a class `container`
46+
el: document.getElementById(to.hash.slice(1)).querySelector('.container')
47+
}
48+
```
49+
50+
# Motivation
51+
52+
## Deprecating `selector`
53+
54+
The existing scroll behavior accepts a `selector` property that internally uses `document.querySelector`. In vue-router@3 we currently have a workaround for selectors that match `/^#\d/` (id CSS selector starting with a number). This is because such selector is invalid, so we detect that and use `document.getElementById` instead. However, this breaks when using CSS combinators like `#1one .container` (select an element with class `.container` inside of an element with id `1one`). The truth is there ary many [others characters that need to be escaped](https://mathiasbynens.be/notes/css-escapes) and that we cannot escape everything, creating cases where the scroll behavior is harder to use. On top of that, it can be confusing for the user when vue-router throws because `document.querySelector` failed.
55+
56+
## Deprecating `x`, `y` and `offset`
57+
58+
Currently there are two ways of specifying an offset and both use an `x`/`y` coordinate system that differs from native functions: native browser functions allow the use of a [`ScrollToOptions`](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions) in `scrollTo` methods. This object contains `top`, `left` and `behavior` properties.
59+
60+
# Detailed design
61+
62+
## Deprecating `x` and `y`
63+
64+
This aligns with [`Element.scrollTo`](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTo) and makes it more natural passing extra options like [`behavior`](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions/behavior).
65+
66+
```js
67+
{ x: 0, y: 200 }
68+
// becomes
69+
{ left: 0, top: 200 }
70+
// it can accept `behavior`
71+
{ left: 0, top: 200, behavior: 'smooth' }
72+
```
73+
74+
## Deprecating `offset`
75+
76+
Instead of taking an `offset` option alongside `selector`, we could directly accept `x` and `y` alongside `selector` when specifying an offset:
77+
78+
```js
79+
{
80+
selector: '#getting-started',
81+
y: -120,
82+
}
83+
```
84+
85+
Which, following the proposed rename, would become
86+
87+
```js
88+
{
89+
el: '#getting-started',
90+
top: -120,
91+
}
92+
```
93+
94+
Omitting `el` will create an absolute offset as if we were providing `x` and/or `y` in vue-router@3.
95+
96+
This also aligns with `new Vue`'s `el` option
97+
98+
## More intuitive selectors thanks to `el`
99+
100+
The goal of a new `el` property, would be to provide simple, _"it just works"_, selectors for most common use cases while still allowing advanced cases:
101+
102+
- `to.hash` refers to an _id_ on the page and is directly provided to `el`. e.g. `el: to.hash` when `to.hash` equals `#about`, `#getting-started`, or `#symbols~work`
103+
- `el` is provided a more generic selector, not necessarily coming from `to.hash`. e.g. `.container > main`, **anything not starting with `#`**
104+
- `el` is provided an `Element` to allow any advanced use case e.g. when `to.hash` starts with `#` but contains a CSS selector rather than an id: `document.querySelector(to.hash)`
105+
106+
Thanks to allowing a raw Element, this covers all possible cases and makes it easier to provide the user with feedback when things do not work.
107+
108+
## Developer experience through warnings
109+
110+
Another important part of this change is warning in development when vue-router fails to find an element or when `document.querySelector` throws an Error. We can divide this in two cases:
111+
112+
### `el` starts with `#`
113+
114+
When `el` starts with `#`, we internally use `document.getElementById(el.slice(1))`. If it doesn't find an element, **in development** mode we try using `document.querySelector`, if we find something, we tell the user to use `el: document.querySelector(${providedEl})` and explain why. If we find nothing, show the usual warning of no element was found
115+
116+
### `el` doesn't start with `#`
117+
118+
In development mode, _try catch_ to provide an error message pointing to this great article https://mathiasbynens.be/notes/css-escapes and to [`CSS.escape`](https://developer.mozilla.org/en-US/docs/Web/API/CSS/escape) if `document.querySelector` throws. If nothing is found, display the same warning of no element was found.
119+
120+
# Drawbacks
121+
122+
- Breaking change but can be introduced through a deprecation
123+
124+
# Adoption strategy
125+
126+
- Deprecate `selector`, `x`, `y` and `offset` with a warning in v3
127+
- Remove in v4
128+
129+
# Notes
130+
131+
- This RFC does not concern scrolling to a different element than window or scrolling multiple elements at once

0 commit comments

Comments
 (0)